查看 jvm GC日志

[TOC]

GC日志閱讀

在開(kāi)發(fā)的世界里揪漩,閱讀日志是最基礎(chǔ)的能力,也是解決問(wèn)題重要的工具惋耙。同樣閱讀gc日志也是解決虛擬機(jī)內(nèi)存的基礎(chǔ)技能虽缕,通過(guò)配置參數(shù)-XX:+PrintGCDetails就可以打印gc日志,建議加上參數(shù)-Xloggc指定gc日志目錄,避免gc日志和console控制臺(tái)日志混亂造成的閱讀困難女淑。
每一種收集器的日志都會(huì)略有不同瞭郑,但會(huì)維持一定的共性,以下面一段日志為例:

0.332: [GC (Allocation Failure) [PSYoungGen: 6120K->504K(6144K)] 12535K->12549K(19968K), 0.0066909 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
0.339: [Full GC (Ergonomics) [PSYoungGen: 504K->0K(6144K)] [ParOldGen: 12045K->10615K(13824K)] 12549K->10615K(19968K), [Metaspace: 3473K->3473K(1056768K)], 0.1372999 secs] [Times: user=0.28 sys=0.00, real=0.14 secs] 

最前面的0.332和0.339代表了gc的發(fā)生的時(shí)間鸭你,它的含義是表達(dá)虛擬機(jī)啟動(dòng)到發(fā)生gc的秒數(shù)屈张。后面的GC和Full GC代表著垃圾收集的停頓類(lèi)型,如果是GC代表的是新生代的GC袱巨,也稱(chēng)ygc和minor gc阁谆,fullgc代表的是對(duì)整堆的一個(gè)gc。后面括號(hào)里的Allocation Failure和Ergonomics代表的是發(fā)生gc的原因愉老,分別是eden區(qū)域空間不夠和parOldGen空間不夠?qū)е碌膅c和fullgc問(wèn)題场绿。以Full GC為例,接下來(lái)的[PSYoungGen嫉入、[ParOldGen焰盗、[Metaspace代表gc發(fā)生的區(qū)域,分別是年輕代劝贸、老年代姨谷、元空間,其名字也是由所使用的gc收集器密切相關(guān)映九,大致如下:

收集器                    顯示區(qū)域
serial                   DefNew
ParNew                   ParNew
Parallel Scavenge        PSYoungGen
serial old               Tenured
parallel old             ParOldGen
CMS                      CMS

后面方括號(hào)內(nèi)部的 504K->0K(6144K)代表著該區(qū)域GC前使用容量-》GC后該區(qū)域所使用容量(該區(qū)域總?cè)萘浚┟蜗妫嚼ㄌ?hào)之外的12549K->10615K(19968K)則代表gc之前堆中使用容量-》gc后堆中使用容量(堆總?cè)萘浚?.1372999 secs這個(gè)很簡(jiǎn)單,代表gc占用時(shí)間件甥,單位是秒捌议。

內(nèi)存分配與回收策略

  • 對(duì)象優(yōu)先在Eden分配

大多數(shù)情況下,對(duì)象優(yōu)先在新生代Eden區(qū)中分配引有。當(dāng)Eden區(qū)域沒(méi)有足夠空間進(jìn)行分配時(shí)瓣颅,將發(fā)生一次Minor GC。虛擬機(jī)提供了-XX:+PrintGCDetails用來(lái)輸出gc日志譬正,此日志會(huì)告訴我們垃圾收集行為時(shí)的內(nèi)存日志宫补,并在進(jìn)程結(jié)束后輸出當(dāng)前內(nèi)存各區(qū)域的分配情況。上例子:

public class TestAllocation {

    private static final int _1MB=1024*1024;

    public static void main(String[] args) {
        byte[] a1,a2,a3,a4;
        a1=new byte[2*_1MB];
        a2=new byte[2*_1MB];
        a3=new byte[2*_1MB];
        a4=new byte[4*_1MB];
    }
}

gc日志如下所示:

"C:\Program Files\Java\jdk1.8.0_151\bin\java" -XX:+PrintGCDetails -Xmx20m -Xms20m -Xmn10m 
[GC (Allocation Failure) [PSYoungGen: 6294K->808K(9216K)] 6294K->4912K(19456K), 0.0023349 secs] [Times: user=0.09 sys=0.00, real=0.02 secs] 
Heap
 PSYoungGen      total 9216K, used 7273K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 78% used [0x00000000ff600000,0x00000000ffc50670,0x00000000ffe00000)
  from space 1024K, 78% used [0x00000000ffe00000,0x00000000ffeca020,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 4104K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 40% used [0x00000000fec00000,0x00000000ff002020,0x00000000ff600000)
 Metaspace       used 3473K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 381K, capacity 388K, committed 512K, reserved 1048576K

其中vm配置參數(shù)從第一行便可知曾我。新生代分為eden區(qū)域和兩塊survior區(qū)域粉怕,默認(rèn)比例為8:1:1,從圖中eden:from:to=8192:1024:1024可以得到驗(yàn)證抒巢。下來(lái)我們就根據(jù)gc日志分析下在執(zhí)行這段程序時(shí)贫贝,jvm究竟都做了哪些事。

image.png

從這張圖片可知,在jdk1.8.0_151中稚晚,即使跑一個(gè)空的main函數(shù)崇堵,新生代就要占2362k,這個(gè)是虛擬機(jī)的初始內(nèi)存占用客燕,好奇寶寶可以通過(guò)jmap命令看看到底堆里裝了什么≡Ю停現(xiàn)在讓我們回到最開(kāi)始代碼中,會(huì)將a1幸逆、a2分配在新生代的eden區(qū)棍辕,此時(shí)eden區(qū)域?yàn)?048k+2048K+2362k=6458k,因?yàn)閑den區(qū)域空間不夠,不足以將a3裝入还绘,此時(shí)觸發(fā)minor gc,又因?yàn)榇藭r(shí)a1楚昭、a2對(duì)象還存活,suivor區(qū)域只有1024k拍顷,故將a1抚太、a2分配擔(dān)保到老年代。從日志中可知昔案,經(jīng)歷過(guò)一次minor gc新生代還有808k的存活對(duì)象尿贫,因?yàn)閍1、a2已經(jīng)擔(dān)保到老年代踏揣,故這是初始內(nèi)存中經(jīng)過(guò)gc存活的對(duì)象庆亡,通過(guò)復(fù)制算法轉(zhuǎn)移到survivor中。此時(shí)eden區(qū)域是0k捞稿,其中一塊survivor是初始內(nèi)存又谋,老年代存放著a1、a2對(duì)象娱局,此時(shí)開(kāi)始繼續(xù)分配對(duì)象內(nèi)存彰亥,因a3+a4<eden區(qū)域,故全部分配在eden區(qū)域衰齐。

  • 大對(duì)象直接進(jìn)入老年代
    哪怕你從來(lái)沒(méi)有學(xué)習(xí)過(guò)jvm知識(shí)任斋,你或許也聽(tīng)說(shuō)過(guò)江湖上流傳著大對(duì)象直接進(jìn)入老年代這個(gè)傳聞。很多人都知道這個(gè)知識(shí)點(diǎn)耻涛,但恐怕大多數(shù)人并不能準(zhǔn)確的去描述這個(gè)分配策略废酷。
    1.何謂大對(duì)象?

所謂大對(duì)象就是需要大量連續(xù)內(nèi)存空間的對(duì)象抹缕,上個(gè)例子中的byte數(shù)組就是典型的大對(duì)象澈蟆。

2.參數(shù)-XX:PretenureSizeThreshold的作用?
虛擬機(jī)提供了-XX:PretenureSizeThreshold歉嗓,令大于這個(gè)值得對(duì)象直接在老年代分配。hotspot可以在年輕代手機(jī)內(nèi)存的收集器有Serial背蟆、ParNew鉴分、Parallel Scavenge以及G1(G1劃分內(nèi)存區(qū)域比較特殊暫不考慮)哮幢。其中只有Serial和ParNew收集器可以識(shí)別這個(gè)參數(shù),Parallel Scavenge是不識(shí)別這個(gè)參數(shù)的志珍,但并不是大對(duì)象直接進(jìn)入老年代分配策略對(duì)其就是無(wú)效的橙垢,在Parallel Scavenge中自有它的實(shí)現(xiàn),大約等于Eden區(qū)域一半的對(duì)象會(huì)被認(rèn)成大對(duì)象伦糯。感興趣的可以來(lái)這看看柜某,傳送門(mén):鏈接描述.如果想要使用-XX:PretenureSizeThreshold參數(shù),可以考慮使用ParNew+CMS的組合敛纲。給大家展示一個(gè)例子:

    public class BigObject {

    public static void main(String[] args) {
        byte[] test = new byte[4*1024*1024];
    }
}
image.png

從gc日志喂击,我們很容易得出大對(duì)象進(jìn)入老年代這個(gè)結(jié)論。對(duì)了淤翔,還需要注意的是XX:PretenureSizeThreshold的單位是k翰绊,不能像-Xmx3mb這樣直接指定。
3.為什么大對(duì)象要進(jìn)入老年代旁壮?
在搞清楚這個(gè)問(wèn)題之前监嗜,我們首先要去揣摩大師們?cè)O(shè)計(jì)分代算法的意圖。設(shè)計(jì)師們希望新生代的對(duì)象多數(shù)是朝生夕滅的抡谐,故新生代采用復(fù)制算法最合適裁奇。復(fù)制算法的優(yōu)點(diǎn)是簡(jiǎn)單,速度快(在存活對(duì)象少的情況下)麦撵,缺點(diǎn)是占內(nèi)存要發(fā)生內(nèi)存復(fù)制刽肠。這樣做的目的就是避免在eden區(qū)和兩個(gè)survivor區(qū)之間發(fā)生大量的內(nèi)存復(fù)制。

  • 長(zhǎng)期存活的對(duì)象將進(jìn)入老年代
    虛擬機(jī)給每個(gè)對(duì)象定義了一個(gè)對(duì)象年齡計(jì)數(shù)器厦坛,保存在對(duì)象頭中的Mark word部分五垮。如果對(duì)象在eden出生,經(jīng)歷過(guò)一次minor gc仍然活著杜秸,并且能被survivor區(qū)容納放仗,將會(huì)被移動(dòng)到survivor區(qū)域,并且將gc年齡設(shè)置為1撬碟,這種對(duì)象沒(méi)經(jīng)歷一次Minor gc 诞挨,年齡就增加一歲,當(dāng)它的年齡增加到一定程度(默認(rèn)是15歲)呢蛤,就會(huì)被晉升到老年代惶傻,這個(gè)年齡閾值可以通過(guò)參數(shù)-XX:MaxTenuringThresold來(lái)設(shè)置.

  • 動(dòng)態(tài)對(duì)象年齡判定
    虛擬機(jī)并不是永遠(yuǎn)要求對(duì)象的年齡永遠(yuǎn)達(dá)到MaxTenuringThresold才能晉升老年代,如果在survivor空間中相同年齡所有的對(duì)象的大小總和大于survivor空間的一半其障,年齡大于或等于改年齡的對(duì)象直接進(jìn)入老年代银室,無(wú)須等到MaxTenuringThresold要求的年齡。

  • 空間分配擔(dān)保
    在發(fā)生minor gc之間,虛擬機(jī)會(huì)先檢查老年代最大可用的連續(xù)空間是否大于新生代所有對(duì)象總空間蜈敢,如果條件成立辜荠,則代表這次gc是安全的。如果不成立抓狭,jdk1.7和jdk1.8的版本中會(huì)繼續(xù)檢查老年代最大的可用空間是否大于歷次晉升到老年代對(duì)象的平均大小伯病,如果小于則進(jìn)行一次full gc,如果大于則嘗試進(jìn)行一次minor gc,如果出現(xiàn)老年代擔(dān)保失敗的情況則會(huì)進(jìn)行一次full gc否过。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末午笛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子苗桂,更是在濱河造成了極大的恐慌药磺,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件誉察,死亡現(xiàn)場(chǎng)離奇詭異与涡,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)持偏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)驼卖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人鸿秆,你說(shuō)我怎么就攤上這事酌畜。” “怎么了卿叽?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵桥胞,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我考婴,道長(zhǎng)贩虾,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任沥阱,我火速辦了婚禮缎罢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘考杉。我一直安慰自己策精,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布崇棠。 她就那樣靜靜地躺著咽袜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪枕稀。 梳的紋絲不亂的頭發(fā)上询刹,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天谜嫉,我揣著相機(jī)與錄音,去河邊找鬼凹联。 笑死骄恶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的匕垫。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼虐呻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼象泵!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起斟叼,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤偶惠,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后朗涩,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體忽孽,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年谢床,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了兄一。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡识腿,死狀恐怖出革,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情渡讼,我是刑警寧澤骂束,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站成箫,受9級(jí)特大地震影響展箱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蹬昌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一混驰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凳厢,春花似錦账胧、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至遮精,卻和暖如春居夹,著一層夾襖步出監(jiān)牢的瞬間败潦,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工准脂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劫扒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓狸膏,卻偏偏與公主長(zhǎng)得像沟饥,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子湾戳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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