JVM 参数(转)
常用的JVM配置參數(shù)
一、Trace 跟蹤參數(shù)
在Eclipse中,如何打開GC的監(jiān)控日志
選擇菜單欄Run -> Run Configurations -> Java Application -> 選擇自己的項(xiàng)目 -> 在右側(cè)找到Arguments選項(xiàng)卡 -> 在VM arguments中填寫參數(shù),具體參數(shù)在下面會(huì)有說明。
根據(jù)右側(cè)Main的project和下面Main?class確定自己監(jiān)控的main方法
在右側(cè)找到Arguments選項(xiàng)卡 -> 在VM arguments中填寫參數(shù)
?
-
-verbose:gc(打開GC的跟蹤日志)
-
-XX:+printGC(打開GC的log的開關(guān),簡(jiǎn)要日志)
上圖為我自己的一個(gè)小項(xiàng)目中的gc簡(jiǎn)要的日志信息?其中 9865k?表示在堆中GC之前使用了9865k的空間,2891k?表示GC之后使用2891k的空間,剩空間為19456k ,本次GC使用的時(shí)間為0.0021802?secs
- ?-XX:+PrintGCDetails(打印GC的詳細(xì)信息)
上圖我們以第二條為例:PSYoungGen表示新生代 GC之前為9214k,GC之后為 1016K,新生代總大小為9216k,GC所使用的時(shí)間為0.0016505?secs。而后面的信息則為上面簡(jiǎn)要信息中的內(nèi)容。user 總計(jì)本次 GC 總線程所占用的總 CPU 時(shí)間 ,sys – OS 調(diào)用 or 等待系統(tǒng)時(shí)間,real – 應(yīng)用暫停時(shí)間,如果GC 線程是 Serial Garbage Collector單線程的方式的話,? real time 等于user 和 system 時(shí)間之和.
?
(def new generation)新生代
(total 13824K)共有13824K空間可用,(used 11223K)有11223K被使用。
(eden space 12288k.91%)伊甸區(qū) 對(duì)象出生的地方有 12288K 的空間,有91%已經(jīng)被占用
(from space 1536K,0%)s0區(qū) 1536K空間,被占用為0
(to space 1536K,0%)s0區(qū) 1536K空間,被占用為0
(tenured generation)老年代
(the space 5120K,0%)有5120K空間被占用為0
(compacting perm gen)永久代
(the space 12288k,1%)有12288K空間被占用為1%,在jdk5.0之后在串行GC下有一個(gè)永久區(qū)共享,打開共享之后一些基礎(chǔ)的java類可用被所有的jvm共同使用,所以被占用率較小.
(ro space 10240K,44%)只讀共享區(qū)間 有10240K空間 44%被占用
(rw space 12288K,52%)可讀可寫共享區(qū)間 有12288K空間,52%被占用
(而最后[]號(hào)中的3個(gè)值為地址值,分別表示當(dāng)前內(nèi)存區(qū)域的地址開始地址,當(dāng)前地址,最大地址上限)
上圖為我自己獲取到的jvm日志信息,永久代被刪除,取而代之的是Metaspace?元數(shù)據(jù)區(qū)域,這是 java8?所做的替換。
持久代中存的內(nèi)容:
元空間的特點(diǎn):
- ?-XX:+PrintGCTimeStamps(打印GC發(fā)生的時(shí)間戳)
- -Xloggc:log/ge.log(指定GC.log的位置,以文件形式輸出)
- -XX:+PrintHeapAtGC(每一次GC后都打印出堆信息)
?Heap before GC 表示GC之前的堆信息
Heap after GC 表示GC之后的堆信息
- -XX:+TraceClassLoading(監(jiān)控類加載,可以在程序運(yùn)行時(shí)檢出哪些類被加載了)
- -XX:+PrintClassHistogram(加入此參數(shù),在運(yùn)行時(shí)不會(huì)有其他東西輸出,但是在按下Ctrl+Break后可以打印出類的信息,類的直方圖)
上述4個(gè)列分別代表了(num)序號(hào),(instances)實(shí)例數(shù)量,(bytes)總占用空間,(class name)類型
([B)有890617個(gè)byte數(shù)組,占用了470266000的空間
(java.util.HashMap$Node)hashMap的結(jié)點(diǎn)有890643個(gè)占用21375432的空間
?
二、堆的分配參數(shù)
- -Xmx(最大堆的空間)
- -Xms(最小堆的空間)
?我們可以通過上述代碼來獲取系統(tǒng)中實(shí)際使用的空間大小。
我們可以看到,我的系統(tǒng)中最大堆空間為18.0M,系統(tǒng)分配到的空間為9.5M,是比較接近于我們自己設(shè)置的值,系統(tǒng)目前可用空間為7.9M,此時(shí)系統(tǒng)存在可用空間。
當(dāng)我在我的系統(tǒng)中加入一行代碼,創(chuàng)建一個(gè)1M的byte數(shù)組
此時(shí)發(fā)現(xiàn),系統(tǒng)可用空間整好少了1M,而總空間和系統(tǒng)中分配到的空間還是沒變的,如果我們的系統(tǒng)使用的空間是小于系統(tǒng)分配的空間時(shí),系統(tǒng)分配空間會(huì)盡可能維持在最小空間10M附近,只有系統(tǒng)使用的空間大于10M后,系統(tǒng)分配空間才會(huì)去擴(kuò)展。我們?cè)诖a中創(chuàng)建一個(gè)10M的byte數(shù)組來看。
?
? 此時(shí),系統(tǒng)使用的空間肯定是大于10M的,所以我們的系統(tǒng)分配的空間已經(jīng)擴(kuò)展到了16M.如果我們創(chuàng)建一個(gè)大于20Mbyte的話就會(huì)發(fā)生OOM了,因?yàn)橄到y(tǒng)已經(jīng)限制最大空間為20M。
?
- -Xmn (設(shè)置新生代的大小)
- -XX:NewRatio(設(shè)置新生代和老年代的比值,如果設(shè)置為4則表示(eden+from(或者叫s0)+to(或者叫s1)): 老年代 =1:4),即年輕代占堆的五分之一
- -XX:SurvivorRatio(設(shè)置兩個(gè)Survivor(幸存區(qū)from和to或者叫s0或者s1區(qū))和eden區(qū)的比),8表示兩個(gè)Survivor:eden=2:8,即Survivor區(qū)占年輕代的五分之一
? ??下面來看一個(gè)例子(jdk6)
//將jvm參數(shù)設(shè)置為-Xmx20m -Xms20m -Xmn1m -XX:+PrintGCDetails(將新生代的大小設(shè)置為1M) byte []b = null; for (int i = 0; i < 10; i++) {b = new byte[1024*1024*1]; }? ? ?上圖為堆信息,沒有發(fā)生過GC,新生代只有896K,1Mbyte無法分配到新生區(qū),所以所有的數(shù)據(jù)都被分配到老年代,老年代的內(nèi)存被占用的為10240K正好是byte的大小。
我們將上述代碼的新生代的內(nèi)存進(jìn)行擴(kuò)大,調(diào)整到15M -Xmx20m -Xms20m -Xmn15m -XX:+PrintGCDetails
?
我們發(fā)現(xiàn)修改新生代之后也沒有發(fā)生GC,而是將數(shù)據(jù)全部分配到了新生代13824K,老年代卻沒有使用。
我們將上述代碼的新生代的內(nèi)存進(jìn)行減小,調(diào)整到不大不小的位置,調(diào)整到7M -Xmx20m -Xms20m -Xmn7m -XX:+PrintGCDetails
此時(shí)發(fā)現(xiàn)GC被觸發(fā)了2次,第一次回收了3M左右,第二次回收了4M左右,此時(shí)發(fā)現(xiàn)新生代被使用1139K,老年代被使用2507K,因?yàn)閒orm to(s0 s1)區(qū)域的大小為704K,不足1M所以才GC時(shí)還是有一部分?jǐn)?shù)據(jù)被放入了老年代。
? 接下來,我們將幸存代的大小進(jìn)行調(diào)整from:to:endn=1:1:2,?-Xmx20m -Xms20m -Xmn7m XX:SurvivorRatio=2 -XX:+PrintGCDetails
?
此時(shí)幸存代可以正常使用,GC發(fā)生了3次。第一次回收了1M,第二次回收了3M,第三次回收了3M,新生代占用了3M,此時(shí)新產(chǎn)生的數(shù)據(jù)沒有進(jìn)入到老年代。
? ? 接下來,繼續(xù)調(diào)整新生代和老年代的比例為1,?-Xmx20m -Xms20m??-XX:NewRatio=1?XX:SurvivorRatio=2 -XX:+PrintGCDetails
?
此時(shí)GC進(jìn)行了2次回收第一次回收了3M,第二次回收了4M,還有3M在新生代,也沒有數(shù)據(jù)進(jìn)入老年代,并且GC只執(zhí)行了2次,所以對(duì)于上一種配置效率就有所提高,因?yàn)镚C時(shí)很消耗效率的。幸存代空間越大,對(duì)系統(tǒng)資源的浪費(fèi)還是挺嚴(yán)重的,所以合理的分配幸存代,堆系統(tǒng)的效率也會(huì)有很大的幫助。
? 接下來,繼續(xù)調(diào)整幸存代的大小進(jìn)行調(diào)整from:to:endn=1:1:3,?-Xmx20m -Xms20m??-XX:NewRatio=1?XX:SurvivorRatio=3 -XX:+PrintGCDetails,此時(shí),from和to的幸存區(qū)有2M,而endn區(qū)有6M
此時(shí)GC只進(jìn)行了1次,我們對(duì)幸存代的大小進(jìn)行了合理的減小,這樣更有利于內(nèi)存的合理使用。
- -XX:+HeapDumpOnOutOfMemoryError(將OOM時(shí)的堆信息導(dǎo)出到文件)
如果系統(tǒng)出現(xiàn)OOM一般情況系統(tǒng)有可能會(huì)down掉,但是我們排查問題時(shí)需要場(chǎng)景重現(xiàn)是比較困難的,所以當(dāng)我們輸出了OOM的異常時(shí),就可以直接查看,找出導(dǎo)致OOM的原因 - -XX:+HeapDumpPath=XXXX(導(dǎo)出OOM堆信息文件的路徑)
- -XX:OnOutOfMemoryError(在系統(tǒng)出現(xiàn)OOM時(shí),執(zhí)行一個(gè)腳本,可以發(fā)送郵件,報(bào)警或者是重啟程序)
- -XX:PermSize(設(shè)置永久代的初始空間大小)
- -XX:MaxParmSize(設(shè)置永久代的最大空間)
在使用CGLIB等庫(kù)的時(shí)候,可能會(huì)產(chǎn)生大量的類,這些類就有可能會(huì)撐爆永久區(qū)導(dǎo)致OOM
我們來看下面實(shí)例:
當(dāng)發(fā)生OOM時(shí),我們發(fā)現(xiàn)永久區(qū)的空間已經(jīng)是滿了,然后發(fā)生GC時(shí)永久區(qū)的內(nèi)容也無法被回收,所以導(dǎo)致了OOM,此時(shí)新生代只占用了2%,老難帶占用了20%,而老年代使用率為99%.
總結(jié):
- 根據(jù)實(shí)際事情調(diào)整新生代和幸存代的大小,因?yàn)楦鱾€(gè)系統(tǒng)的情況都不一樣,所以需要自己調(diào)試而找到一個(gè)相對(duì)較優(yōu)的分配方案。
- 官方推薦新生代占堆的3/8
- 幸存代占新生代的1/10
- 在OOM時(shí),及得Dump出堆,確保可以排查現(xiàn)場(chǎng)問題
- 在堆空間沒有使用完時(shí)也有可能會(huì)產(chǎn)生OOM,此時(shí)有可能是永久代被撐爆。
三、棧大小的分配
棧是每一個(gè)線程都有的,他是線程私有的一塊內(nèi)存區(qū)域.棧中主要是由幀組成,而幀中是每個(gè)方法的局部變量表,操作數(shù)表,和指向常量池的引用和返回地址等組成。一般只有幾百K,但是它的大小決定了線程的多少和調(diào)用函數(shù)的深度,而且每個(gè)線程都有獨(dú)立的棧空間。
- -Xss(設(shè)置棧空間的大小)
下面看一個(gè)簡(jiǎn)單的例子:首先我們將棧空間設(shè)置為128K
此時(shí)只執(zhí)行了323次的遞歸。
然后我們將棧空間擴(kuò)大到256K再來看結(jié)果:
?
? ? 此時(shí)遞歸執(zhí)行竟然擴(kuò)大到了1019,接近3倍,那么說明方法執(zhí)行的深度由棧空間的大小所決定。
然后我們將局部變量e之后的局部變量都清除再來看結(jié)果:
?
我們發(fā)現(xiàn),遞歸次數(shù)再次增加。此處說明方法執(zhí)行的深度也由方法內(nèi)局部變量表的個(gè)數(shù)所決定。
轉(zhuǎn)載于:https://www.cnblogs.com/xuningchuanblogs/p/11441520.html
總結(jié)
- 上一篇: Codeforces 1206
- 下一篇: JVM 常用参数一览表(转)