常用的JVM配置參數(shù)

一氮凝、Trace 跟蹤參數(shù)

在Eclipse中查牌,如何打開GC的監(jiān)控日志
    選擇菜單欄Run -> Run Configurations -> Java Application -> 選擇自己的項目 -> 在右側找到Arguments選項卡 -> 在VM arguments中填寫參數(shù)栅哀,具體參數(shù)在下面會有說明会通。

image

根據(jù)右側Main的project和下面Main class確定自己監(jiān)控的main方法

image

在右側找到Arguments選項卡 -> 在VM arguments中填寫參數(shù)

image
  • -verbose:gc(打開GC的跟蹤日志)

  • -XX:+printGC(打開GC的log的開關丑婿,簡要日志)

image

上圖為我自己的一個小項目中的gc簡要的日志信息 其中 9865k 表示在堆中GC之前使用了9865k的空間性雄,2891k 表示GC之后使用2891k的空間,矢睿空間為19456k 秒旋,本次GC使用的時間為0.0021802 secs

  • -XX:+PrintGCDetails(打印GC的詳細信息)
image

上圖我們以第二條為例:PSYoungGen表示新生代 GC之前為9214k,GC之后為 1016K诀拭,新生代總大小為9216k迁筛,GC所使用的時間為0.0016505 secs。而后面的信息則為上面簡要信息中的內(nèi)容耕挨。user 總計本次 GC 總線程所占用的總 CPU 時間 细卧,sys – OS 調(diào)用 or 等待系統(tǒng)時間,real – 應用暫停時間筒占,如果GC 線程是 Serial Garbage Collector單線程的方式的話贪庙, real time 等于user 和 system 時間之和.

image

(def new generation)新生代
(total 13824K)共有13824K空間可用,(used 11223K)有11223K被使用翰苫。
(eden space 12288k.91%)伊甸區(qū) 對象出生的地方有 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下有一個永久區(qū)共享,打開共享之后一些基礎的java類可用被所有的jvm共同使用滑沧,所以被占用率較小.
(ro space 10240K并村,44%)只讀共享區(qū)間 有10240K空間 44%被占用
(rw space 12288K,52%)可讀可寫共享區(qū)間 有12288K空間滓技,52%被占用

(而最后[]號中的3個值為地址值哩牍,分別表示當前內(nèi)存區(qū)域的地址開始地址,當前地址令漂,最大地址上限)

image

上圖為我自己獲取到的jvm日志信息膝昆,永久代被刪除,取而代之的是Metaspace 元數(shù)據(jù)區(qū)域叠必,這是 java8 所做的替換荚孵。

持久代中存的內(nèi)容:

  1. JVM中類的元數(shù)據(jù)在Java堆中的存儲區(qū)域。
  2. Java類對應的HotSpot虛擬機中的內(nèi)部表示纬朝。
  3. 類的層級信息收叶,字段,名字共苛。
  4. 方法的編譯信息及字節(jié)碼判没。
  5. 變量
  6. 常量池和符號解析

元空間的特點:

  1. 充分利用了Java語言規(guī)范中的好處:類及相關的元數(shù)據(jù)的生命周期與類加載器的一致。
  2. 每個加載器有專門的存儲空間
  3. 只進行線性分配
  4. 不會單獨回收某個類
  5. 省掉了GC掃描及壓縮的時間
  6. 元空間里的對象的位置是固定的
  7. 如果GC發(fā)現(xiàn)某個類加載器不再存活了隅茎,會把相關的空間整個回收掉
  • -XX:+PrintGCTimeStamps(打印GC發(fā)生的時間戳)

  • -Xloggc:log/ge.log(指定GC.log的位置澄峰,以文件形式輸出)

  • -XX:+PrintHeapAtGC(每一次GC后都打印出堆信息)

image

Heap before GC 表示GC之前的堆信息
   Heap after GC 表示GC之后的堆信息

  • -XX:+TraceClassLoading(監(jiān)控類加載,可以在程序運行時檢出哪些類被加載了)
image
  • -XX:+PrintClassHistogram(加入此參數(shù)辟犀,在運行時不會有其他東西輸出摊阀,但是在按下Ctrl+Break后可以打印出類的信息,類的直方圖)
image

上述4個列分別代表了(num)序號,(instances)實例數(shù)量,(bytes)總占用空間踪蹬,(class name)類型
   “恕([B)有890617個byte數(shù)組,占用了470266000的空間
   ≡镜贰(java.util.HashMap$Node)hashMap的結點有890643個占用21375432的空間

二漱牵、堆的分配參數(shù)

  • -Xmx(最大堆的空間)
  • -Xms(最小堆的空間)
image

<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">System.out.println("系統(tǒng)最大使用空間:Xmx=" + Runtime.getRuntime().maxMemory()/1024.0/1024 + "M");
System.out.println("系統(tǒng)可用空間:free mem=" + Runtime.getRuntime().freeMemory()/1024.0/1024 + "M");
System.out.println("系統(tǒng)中分配到的空間:total mem=" + Runtime.getRuntime().totalMemory()/1024.0/1024 + "M");</pre>

我們可以通過上述代碼來獲取系統(tǒng)中實際使用的空間大小。

image

我們可以看到疚漆,我的系統(tǒng)中最大堆空間為18.0M酣胀,系統(tǒng)分配到的空間為9.5M刁赦,是比較接近于我們自己設置的值,系統(tǒng)目前可用空間為7.9M闻镶,此時系統(tǒng)存在可用空間甚脉。
  當我在我的系統(tǒng)中加入一行代碼,創(chuàng)建一個1M的byte數(shù)組

<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">byte []b = new byte[102410241];</pre>

image

此時發(fā)現(xiàn)铆农,系統(tǒng)可用空間整好少了1M牺氨,而總空間和系統(tǒng)中分配到的空間還是沒變的,如果我們的系統(tǒng)使用的空間是小于系統(tǒng)分配的空間時墩剖,系統(tǒng)分配空間會盡可能維持在最小空間10M附近猴凹,只有系統(tǒng)使用的空間大于10M后,系統(tǒng)分配空間才會去擴展岭皂。我們在代碼中創(chuàng)建一個10M的byte數(shù)組來看郊霎。

image

此時,系統(tǒng)使用的空間肯定是大于10M的爷绘,所以我們的系統(tǒng)分配的空間已經(jīng)擴展到了16M.如果我們創(chuàng)建一個大于20Mbyte的話就會發(fā)生OOM了书劝,因為系統(tǒng)已經(jīng)限制最大空間為20M。

image
  • -Xmn (設置新生代的大小)
  • -XX:NewRatio(設置新生代和老年代的比值土至,如果設置為4則表示(eden+from(或者叫s0)+to(或者叫s1)): 老年代 =1:4)购对,即年輕代占堆的五分之一
  • -XX:SurvivorRatio(設置兩個Survivor(幸存區(qū)from和to或者叫s0或者s1區(qū))和eden區(qū)的比),8表示兩個Survivor:eden=2:8毙籽,即Survivor區(qū)占年輕代的五分之一

下面來看一個例子(jdk6)

<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">//將jvm參數(shù)設置為-Xmx20m -Xms20m -Xmn1m -XX:+PrintGCDetails(將新生代的大小設置為1M)
byte []b = null; for (int i = 0; i < 10; i++) {
b = new byte[102410241];
}</pre>

image

上圖為堆信息,沒有發(fā)生過GC毡庆,新生代只有896K坑赡,1Mbyte無法分配到新生區(qū),所以所有的數(shù)據(jù)都被分配到老年代么抗,老年代的內(nèi)存被占用的為10240K正好是byte的大小毅否。
  我們將上述代碼的新生代的內(nèi)存進行擴大,調(diào)整到15M -Xmx20m -Xms20m -Xmn15m -XX:+PrintGCDetails

image

我們發(fā)現(xiàn)修改新生代之后也沒有發(fā)生GC措译,而是將數(shù)據(jù)全部分配到了新生代13824K髓涯,老年代卻沒有使用祠斧。

我們將上述代碼的新生代的內(nèi)存進行減小,調(diào)整到不大不小的位置捆探,調(diào)整到7M -Xmx20m -Xms20m -Xmn7m -XX:+PrintGCDetails

image

此時發(fā)現(xiàn)GC被觸發(fā)了2次,第一次回收了3M左右站粟,第二次回收了4M左右黍图,此時發(fā)現(xiàn)新生代被使用1139K,老年代被使用2507K奴烙,因為form to(s0 s1)區(qū)域的大小為704K助被,不足1M所以才GC時還是有一部分數(shù)據(jù)被放入了老年代剖张。

接下來,我們將幸存代的大小進行調(diào)整from:to:endn=1:1:2揩环, -Xmx20m -Xms20m -Xmn7m XX:SurvivorRatio=2 -XX:+PrintGCDetails

image

此時幸存代可以正常使用搔弄,GC發(fā)生了3次。第一次回收了1M丰滑,第二次回收了3M顾犹,第三次回收了3M,新生代占用了3M吨枉,此時新產(chǎn)生的數(shù)據(jù)沒有進入到老年代蹦渣。

接下來,繼續(xù)調(diào)整新生代和老年代的比例為1貌亭, -Xmx20m -Xms20m -XX:NewRatio=1 XX:SurvivorRatio=2 -XX:+PrintGCDetails

image

此時GC進行了2次回收第一次回收了3M柬唯,第二次回收了4M,還有3M在新生代圃庭,也沒有數(shù)據(jù)進入老年代锄奢,并且GC只執(zhí)行了2次,所以對于上一種配置效率就有所提高剧腻,因為GC時很消耗效率的拘央。幸存代空間越大,對系統(tǒng)資源的浪費還是挺嚴重的书在,所以合理的分配幸存代灰伟,堆系統(tǒng)的效率也會有很大的幫助。

接下來儒旬,繼續(xù)調(diào)整幸存代的大小進行調(diào)整from:to:endn=1:1:3栏账, -Xmx20m -Xms20m -XX:NewRatio=1 XX:SurvivorRatio=3 -XX:+PrintGCDetails,此時栈源,from和to的幸存區(qū)有2M挡爵,而endn區(qū)有6M

image

此時GC只進行了1次,我們對幸存代的大小進行了合理的減小甚垦,這樣更有利于內(nèi)存的合理使用茶鹃。

  • -XX:+HeapDumpOnOutOfMemoryError(將OOM時的堆信息導出到文件)
    如果系統(tǒng)出現(xiàn)OOM一般情況系統(tǒng)有可能會down掉,但是我們排查問題時需要場景重現(xiàn)是比較困難的艰亮,所以當我們輸出了OOM的異常時闭翩,就可以直接查看,找出導致OOM的原因

  • -XX:+HeapDumpPath=XXXX(導出OOM堆信息文件的路徑)

  • -XX:OnOutOfMemoryError(在系統(tǒng)出現(xiàn)OOM時迄埃,執(zhí)行一個腳本男杈,可以發(fā)送郵件,報警或者是重啟程序)

  • -XX:PermSize(設置永久代的初始空間大械鞣)

  • -XX:MaxParmSize(設置永久代的最大空間)

在使用CGLIB等庫的時候伶棒,可能會產(chǎn)生大量的類旺垒,這些類就有可能會撐爆永久區(qū)導致OOM
    我們來看下面實例:

<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">for (int i = 0; i < 100000; i++) {
CglibBean c = new CglibBean(new HashMap<String, String>());
}</pre>

image

當發(fā)生OOM時,我們發(fā)現(xiàn)永久區(qū)的空間已經(jīng)是滿了肤无,然后發(fā)生GC時永久區(qū)的內(nèi)容也無法被回收先蒋,所以導致了OOM,此時新生代只占用了2%宛渐,老難帶占用了20%竞漾,而老年代使用率為99%.

總結:

  • 根據(jù)實際事情調(diào)整新生代和幸存代的大小,因為各個系統(tǒng)的情況都不一樣窥翩,所以需要自己調(diào)試而找到一個相對較優(yōu)的分配方案业岁。
  • 官方推薦新生代占堆的3/8
  • 幸存代占新生代的1/10
  • 在OOM時,及得Dump出堆寇蚊,確北适保可以排查現(xiàn)場問題
  • 在堆空間沒有使用完時也有可能會產(chǎn)生OOM,此時有可能是永久代被撐爆仗岸。

三允耿、棧大小的分配

棧是每一個線程都有的,他是線程私有的一塊內(nèi)存區(qū)域.棧中主要是由幀組成扒怖,而幀中是每個方法的局部變量表较锡,操作數(shù)表,和指向常量池的引用和返回地址等組成盗痒。一般只有幾百K蚂蕴,但是它的大小決定了線程的多少和調(diào)用函數(shù)的深度,而且每個線程都有獨立的椄┑耍空間骡楼。

  • -Xss(設置棧空間的大锌闯伞)
    下面看一個簡單的例子:首先我們將椌啵空間設置為128K

[
復制代碼

](javascript:void(0); "復制代碼")

<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">private static int count = 0; public static void recursion(long a, long b, long c) { long e = 1, f = 2, g = 3, h = 4, i = 5, j = 6, k = 7, l = 8, m = 9;
count ++;
recursion(a, b, c);
} public static void main(String[] args) { try {
recursion(1, 2, 3);
} catch (Throwable e) {
System.out.println("deep of calling = " + count);
e.printStackTrace();
}
}</pre>

[
復制代碼

](javascript:void(0); "復制代碼")

image

此時只執(zhí)行了323次的遞歸跨嘉。

  然后我們將棿ɑ牛空間擴大到256K再來看結果:

image

此時遞歸執(zhí)行竟然擴大到了1019,接近3倍祠乃,那么說明方法執(zhí)行的深度由椕沃兀空間的大小所決定。

然后我們將局部變量e之后的局部變量都清除再來看結果:

image

我們發(fā)現(xiàn)亮瓷,遞歸次數(shù)再次增加琴拧。此處說明方法執(zhí)行的深度也由方法內(nèi)局部變量表的個數(shù)所決定。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嘱支,一起剝皮案震驚了整個濱河市蚓胸,隨后出現(xiàn)的幾起案子挣饥,更是在濱河造成了極大的恐慌,老刑警劉巖沛膳,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扔枫,死亡現(xiàn)場離奇詭異,居然都是意外死亡锹安,警方通過查閱死者的電腦和手機短荐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來叹哭,“玉大人忍宋,你說我怎么就攤上這事》缯郑” “怎么了糠排?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長泊交。 經(jīng)常有香客問我乳讥,道長,這世上最難降的妖魔是什么廓俭? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任云石,我火速辦了婚禮,結果婚禮上研乒,老公的妹妹穿的比我還像新娘汹忠。我一直安慰自己,他們只是感情好雹熬,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布宽菜。 她就那樣靜靜地躺著,像睡著了一般竿报。 火紅的嫁衣襯著肌膚如雪铅乡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天烈菌,我揣著相機與錄音阵幸,去河邊找鬼。 笑死芽世,一個胖子當著我的面吹牛挚赊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播济瓢,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼荠割,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了旺矾?” 一聲冷哼從身側響起蔑鹦,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤夺克,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后嚎朽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體懊直,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年火鼻,在試婚紗的時候發(fā)現(xiàn)自己被綠了室囊。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡魁索,死狀恐怖融撞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情粗蔚,我是刑警寧澤尝偎,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站鹏控,受9級特大地震影響致扯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜当辐,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一抖僵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧缘揪,春花似錦耍群、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至袖裕,卻和暖如春曹抬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背急鳄。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工谤民, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人攒岛。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓赖临,卻偏偏與公主長得像胞锰,于是被迫代替她去往敵國和親灾锯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容