G1 GC log的解讀

G1 GC知識(shí)點(diǎn):

Region:1M~64M,2的冪,默認(rèn)為其大小為將堆分為約2048個(gè)region為宜??梢酝ㄟ^(guò)-XX:G1HeapRegionSize來(lái)設(shè)定region大小,但是不推薦這么做,region過(guò)少會(huì)導(dǎo)致G1的靈活性降低,掃描的時(shí)間增長(zhǎng)。

free list:由空的region組成的linked list

GC 過(guò)程如下:

1.當(dāng)一個(gè)對(duì)象需要分配時(shí),首先從free list里獲取一個(gè)region的TLAB(Thread Local Allocation Buffer)本地線程緩沖區(qū),然后在這個(gè)TLAB上進(jìn)行分配。

2. 以此類(lèi)推,直到所有Eden的region的總量都被填滿,就會(huì)觸發(fā)一次young GC。這里的cumulative amount of Eden space 跟目標(biāo)暫停時(shí)間有關(guān),在堆的5%~60%之間波動(dòng),其大小跟上次young GC的表現(xiàn)有關(guān)。

3. 當(dāng)上述young GC完成后,死亡的對(duì)象被回收,存活的對(duì)象經(jīng)過(guò)疏散和壓縮后拷貝到Survivor區(qū),而年齡超過(guò)閾值(可以通過(guò)MaxTenuringThreshold設(shè)置,默認(rèn)15)的則會(huì)晉升到old區(qū)。

4. 如果滿足如下三種情況之一,G1收集會(huì)繼續(xù)

? ? a. occupancy higher than threshold?達(dá)到the InitiatingHeapOccupancyPercent (IHOP),old regions里分配的對(duì)象大于堆的45%(G1HeapWastePercent參數(shù))

? ? b. candidate old regions available 達(dá)到G1ReservePercent (G1MixedGCLiveThresholdPercent defaults to 85% in JDK8u40+ and 65% in JDK7)

? ? c. 遇到巨型數(shù)據(jù)的分配

5. 并發(fā)標(biāo)記。基于snapshot-at-the-beginning (SATB)標(biāo)記算法,在GC開(kāi)始時(shí)先創(chuàng)建一個(gè)對(duì)象快照,STAB可以在并發(fā)標(biāo)記時(shí)標(biāo)記所有快照中當(dāng)時(shí)的存活對(duì)象。標(biāo)記過(guò)程中新分配的對(duì)象也會(huì)被標(biāo)記為存活對(duì)象,不會(huì)被回收。

6. 當(dāng)并發(fā)標(biāo)記完成后,會(huì)再觸發(fā)一個(gè)young GC,然后再出發(fā)一個(gè)mixed GC。mixed GC與young GC主要有2點(diǎn)不同,mixed GC會(huì)回收包括Eden和old區(qū)的對(duì)象,二者觸發(fā)的條件不一樣。



初級(jí)標(biāo)記(Mandatory):

根據(jù)參數(shù)‘-XX:+PrintGCDetails’,產(chǎn)生如下log

1. 信息總覽:

????a. 通過(guò)設(shè)置?‘-XX:+PrintGCDateStamps’ 得到GC發(fā)生的準(zhǔn)備日期時(shí)間 -?2016-12-12T10:40:18.811-0500

? ? b. JVM啟動(dòng)到當(dāng)前時(shí)間的相對(duì)時(shí)間?-?29.959

? ? c. 收集的類(lèi)型?-?G1 Evacuation Pause (young)

? ? d. 垃圾收集消耗的總時(shí)長(zhǎng)?-?0.0305171 sec?

2. 并行任務(wù):

? ? a.?Parallel Time - 并行任務(wù)STW總時(shí)長(zhǎng)?- 26.6ms

? ? b. GC Workers?- 并行GC workers的總數(shù)量,通過(guò)?"-XX:ParallelGCThreads"設(shè)置 - 4

? ? ? ? i. 當(dāng)cpu內(nèi)核數(shù) <= 8,設(shè)置為cpu核數(shù);>8時(shí),設(shè)置為核數(shù)的5/8

? ? c.?GC Worker Start?- GCworker開(kāi)始工作時(shí)間相對(duì)于JVM啟動(dòng)的最大最小時(shí)間,diff就是第一個(gè)線程啟動(dòng)與最后一個(gè)線程啟動(dòng)時(shí)間之差,這個(gè)差值肯定越小越好

? ? d.?Ext?Root Scanning - 外部根區(qū)(堆外區(qū),線程棧根,JNI,全局變量,系統(tǒng)目錄,classloader等)掃描消耗時(shí)間

? ? e.?Update RS (Remembered Set or RSet) - 在每次開(kāi)始收集之前都要進(jìn)行Rset更新,保證RSet是最新的。-XX:MaxGCPauseMillis參數(shù)是限制G1的暫停時(shí)間,一般RSet更新的時(shí)間小于10%的目標(biāo)暫停時(shí)間是比較可取的。如果花費(fèi)在RSetUpdate的時(shí)間過(guò)長(zhǎng),可以修改其占用總暫停時(shí)間的百分比-XX:G1RSetUpdatingPauseTimePercent。這個(gè)參數(shù)的默認(rèn)值是10。

? ? f.? Scan RS?- 掃描每個(gè)Region的RSet,尋找被待收集集合引用的區(qū)域? ??

? ? g. Code Root Scanning?- 掃描被待收集集合引用的編譯源碼根節(jié)點(diǎn)

? ? h.?Object Copy - 將待收集集合中所有存活的對(duì)象拷貝到新的區(qū)域

? ? i.? Termination?- 當(dāng)一個(gè)GC worker結(jié)束工作后,需要等待其他線程,并嘗試幫其他線程完成為完成的task. 結(jié)束時(shí)間指的就是這個(gè)線程結(jié)束收集到真正結(jié)束的時(shí)間差

? ? j. GC Worker Other?-?花在GC之外的工作線程的時(shí)間,比如因?yàn)镴VM的某個(gè)活動(dòng),導(dǎo)致GC線程被停掉。這部分消耗的時(shí)間不是真正花在GC上,只是作為log的一部分記錄

? ? k.?GC Worker Total - 每個(gè)并行回收線程的時(shí)間統(tǒng)計(jì)

? ? l. GC Worker End?- GC相對(duì)于JVM啟動(dòng)的結(jié)束時(shí)間. diff指第一個(gè)和最后一個(gè)完成的線程之間差值,越小越好

3. 串行任務(wù):

? ? a.?Code Root Fixup - 遍歷那些指向CSet的方法,修正指針

? ? b.?Code Root Purge - 清理code root table

? ? c.?Clear CT?- 清除card table里的臟cards

4. 其他串行操作:

? ? a.?Choose CSet - 選取CSet

? ? b.?Ref Proc - 處理STW引用處理器發(fā)現(xiàn)的soft/weak/final/phantom/JNI引用

? ? c. Ref?Enq?- 將引用排列到相應(yīng)的reference隊(duì)列里

? ? d. Reditry?Cards?- 在回收過(guò)程中被修改的cards標(biāo)記為臟卡

? ? e. Humongous Register?- 在youngGC的時(shí)候會(huì)收集巨型區(qū)域。這個(gè)指標(biāo)是指評(píng)估巨型區(qū)域是否足夠記錄的時(shí)間。

? ? f.?Humongous Reclaim - 確認(rèn)巨型對(duì)象死亡并清理,釋放巨型對(duì)象區(qū)域,重置區(qū)域類(lèi)型,將該區(qū)域放回空閑隊(duì)列所用的時(shí)間

? ? g. Free CSet?-?釋放CSet,其中也會(huì)清理CSet中的RSet,將其放回空閑隊(duì)列

5. 各個(gè)代的變化統(tǒng)計(jì)

? ? a.?Eden: 1097.0M(1097.0M)->0.0B(967.0M)

? ? ? ? i. 該次Young GC被觸發(fā)是因?yàn)镋den區(qū)滿了

? ? ? ? ii. Eden區(qū)通過(guò)該次垃圾回收被清空,變?yōu)?.0B

? ? ? ? iii. Eden區(qū)的總?cè)萘孔兓?097M -> 967M

? ? b.?Survivors: 13.0M->139.0M

? ? ? ? i. Survivor space從13M增長(zhǎng)到139M

? ? c.?Heap: 1694.4M(2048.0M)->736.3M(2048.0M)

? ? ? ? i. 收集的時(shí)候,整個(gè)堆總量為2048M,被使用了1694M

? ? ? ? ii. 回收完畢,整個(gè)堆總量為2048M,被使用了736.3M

6. 垃圾回收花費(fèi)的時(shí)間

? ? a.?user=0.08 - 在回收過(guò)程中花費(fèi)在用戶代碼上的CPU時(shí)間,是所有thread在所有CPU上的花費(fèi)時(shí)間之和。并沒(méi)有計(jì)算處理器之外花費(fèi)的時(shí)間和等待時(shí)間

? ? b.?sys=0.00 -?在回收過(guò)程中花費(fèi)在內(nèi)核處理上的CPU時(shí)間,是所有thread在所有CPU上的花費(fèi)時(shí)間之和。并沒(méi)有計(jì)算處理器之外花費(fèi)的時(shí)間和等待時(shí)間

? ? c.?real=0.03 - 從垃圾回收到結(jié)束的真實(shí)時(shí)間,包括其他處理器花費(fèi)的時(shí)候及等待時(shí)間

并發(fā)標(biāo)記的分析,并發(fā)標(biāo)記可以由不同的方式觸發(fā),但是它的表現(xiàn)是一致的。

1. 標(biāo)記開(kāi)始:

? ? GC pause (G1 Evacuation Pause) (young) (initial-mark)

? ? 標(biāo)記GC Roots,會(huì)STW,尋找所有可達(dá)到的對(duì)象,初始標(biāo)記階段是Young GC的一部分。初始標(biāo)記階段設(shè)置2種TAMS變量來(lái)區(qū)分現(xiàn)存的對(duì)象和并行標(biāo)記時(shí)才分配的對(duì)象。上述被標(biāo)記的對(duì)象被認(rèn)為是存貨的對(duì)象。

2. 第一次并發(fā)事件:

? ? GC concurrent-root-region-scan-start /?GC concurrent-root-region-scan-end

? ? 根分區(qū)掃描,這個(gè)階段GC的線程可以和應(yīng)用線程并發(fā)運(yùn)行。其主要掃描初始標(biāo)記以及之前YoungGC對(duì)象轉(zhuǎn)移到的Survivor分區(qū),并標(biāo)記Survivor區(qū)中引用的對(duì)象。

3. 并發(fā)標(biāo)記

????GC concurrent-mark-start /?GC concurrent-mark-end

? ? a. 跟應(yīng)用線程同時(shí)運(yùn)行,并發(fā)標(biāo)記的線程數(shù)默認(rèn)為parallel thread的25%,也可以通過(guò)”-XX:ConcGCThreads” 設(shè)置

? ? b.?會(huì)并發(fā)標(biāo)記所有非完全空閑的分區(qū)的存活對(duì)象,也即使用了SATB算法,標(biāo)記各個(gè)分區(qū)

4. 最終標(biāo)記

? ??GC remark [ Finalize Marking / GC ref-proc / Unloading]

? ? 有STW,主要處理SATB緩沖區(qū),以及并發(fā)標(biāo)記階段未標(biāo)記到的漏網(wǎng)之魚(yú)(存活對(duì)象)

5.?清除階段

? ? ?GC cleanup 有STW

? ? a. 每個(gè)區(qū)域分別統(tǒng)計(jì)存活對(duì)象。在card bitmap標(biāo)記初始標(biāo)記之后分配的對(duì)象,在Region bitmap標(biāo)記有存貨對(duì)象的區(qū)域

? ? b. 交換bitmaps,為下一次標(biāo)記做準(zhǔn)備

? ? c. 釋放和清理死去的老年區(qū)域和沒(méi)有存貨數(shù)據(jù)的巨型數(shù)據(jù)區(qū)域

? ? d. 清除沒(méi)有存活對(duì)象的區(qū)域的RSet

? ? e. 將老年區(qū)域根據(jù)存活率進(jìn)行排序

? ? f.? 并發(fā)的將無(wú)效的類(lèi)從metaspace卸載

6. 并發(fā)清除

? ??GC concurrent-cleanup-start /?GC concurrent-cleanup-end

? ? a. 清理RSet,包括card cache和code root table

? ? b. 當(dāng)區(qū)域完全清除后,添加到臨時(shí)隊(duì)列,當(dāng)清除結(jié)束后,將臨時(shí)隊(duì)列合并到第二空閑區(qū)域隊(duì)列,等待被添加到主空閑隊(duì)列

當(dāng)并發(fā)標(biāo)記結(jié)束,Young GC后會(huì)跟緊一個(gè)Mixed GC。Mixed GC跟Young GC只有2點(diǎn)不同,如下:

1. 收集類(lèi)型為混合的:?GC pause (G1 Evacuation Pause) (mixed)

2. CSet會(huì)包含通過(guò)并發(fā)標(biāo)記確定的老年區(qū)域

最后一種可能遇到的GC為Full GC,F(xiàn)ull GC是一個(gè)單線程的有STW的過(guò)程。

1. GC 產(chǎn)生原因,(Allocation Failure)。

2. Full GC的頻率

3. Full GC的消耗時(shí)間


加入‘-XX:+PrintGCApplicationStoppedTime’ and ‘-XX:+PrintGCApplicationConcurrentTime’配置產(chǎn)生的log

1. 業(yè)務(wù)線程在安全點(diǎn)停止的時(shí)間

2. 將所有線程帶到安全點(diǎn)并暫停的耗時(shí)

3. 業(yè)務(wù)線程在兩個(gè)安全點(diǎn)之間運(yùn)行的時(shí)間

高級(jí)標(biāo)記(Advanced)

‘-XX:+PrintAdaptiveSizePolicy’:增加G1 ergonomics,便于對(duì)CSet選擇和暫停時(shí)間的估算有更深入的了解。

對(duì)于Young GC,新增了如下log:

1. dirty card queue 有多少cards待處理,并預(yù)估時(shí)間

2. 該次收集有多少region參與,并預(yù)估時(shí)間,并預(yù)估對(duì)象拷貝的時(shí)間

3. 最終CSet的選擇,并預(yù)估總時(shí)間,其實(shí)就是前兩部之和

4. 不一定出現(xiàn)。如果GC線程執(zhí)行時(shí)間/業(yè)務(wù)線程執(zhí)行時(shí)間大于某個(gè)閾值,G1會(huì)嘗試增大堆。不過(guò)我們的設(shè)置都是max=min,不會(huì)出現(xiàn)這個(gè)

5. 如果需要并發(fā)標(biāo)記會(huì)有這行l(wèi)og。

如果有并發(fā)階段,會(huì)多打印如下log:

當(dāng)標(biāo)記結(jié)束,緊著是mixed GC,多增如下log:

開(kāi)始mixed GC的原因,可回收的old區(qū)域>閾值。如果可回收的小于閾值,則不會(huì)開(kāi)始。

Mixed GC開(kāi)始:

1. 選擇CSet和為CSet添加young region跟Young GC一樣

2. 將Old Region添加到CSet。添加的old region的數(shù)量由參數(shù)XX:G1OldCSetRegionThresholdPercent=X控制,默認(rèn)為10%

3. 總結(jié)CSet的情況,并預(yù)測(cè)總的暫停時(shí)間

4. 展示了Mixed GC循環(huán)的詳細(xì)信息。由于釋放后,任然占堆的14%,大于閾值5%,所以下一次垃圾回收還是Mixed

下一次Mixed垃圾回收跟上面的一致,但是結(jié)尾處有點(diǎn)區(qū)別:

1. 由于這次混合垃圾回收之后,old region的占比小于閾值,故下次垃圾回收為young gc

最后,看一下Full GC的ergonomics

1. 在主從空閑隊(duì)列中均沒(méi)有空閑區(qū)域了,分配請(qǐng)求失敗,需要請(qǐng)求堆擴(kuò)展。

2. 堆擴(kuò)展請(qǐng)求。 但是1.2兩步中的操作還沒(méi)真正實(shí)施

3. 對(duì)擴(kuò)展不會(huì)嘗試,由于可用的未提交的regions數(shù)量為0。由于擴(kuò)展失敗,所以開(kāi)始Full GC

4. 由于堆的最小值小于堆的最大值,G1會(huì)在Full GC之后縮小堆的總量至70%

5. 堆縮小的詳細(xì)信息

-XX:+PrintTenuringDistribution 這個(gè)標(biāo)簽提供了survivor空間的分布

任期分布數(shù)據(jù)主要告訴我們survivor空間如下三點(diǎn)信息:

? ? a. The desired survivor size 就是survivor空間總量 乘以?TargetSurvivorRatio (默認(rèn)值為 50%)

? ? b.?The target threshold 就是對(duì)象在Young GC時(shí)存活的歲數(shù)。

? ? c. 年齡的分布,包括不同年齡對(duì)象的大小及增量的總和。

問(wèn)題診斷標(biāo)記(Debug)

‘-XX:+G1PrintHeapRegions’:?

調(diào)試如下問(wèn)題時(shí)有必要打印堆區(qū)事件:

? ? a. 調(diào)試尋找疏散失敗的原因及失敗區(qū)域的編號(hào)

? ? b. 確定巨型對(duì)象的大小和出現(xiàn)頻率

? ? c. 跟蹤和估算被規(guī)劃為CSet的Eden、Survivor和Old區(qū)的數(shù)量

1. COMMIT

? ? 堆的初始化或擴(kuò)展完成,確定區(qū)域的頂和底

2.?ALLOC(Eden)

? ? 分配的Eden區(qū)域,由底的地址確定

3.?CSET

? ? CSet區(qū)域,該區(qū)域?qū)⒈换厥?,由底的地址確定

4. CLEANUP

? ? 在并發(fā)標(biāo)記的時(shí)候完全被清空的區(qū)域,由底的地址確定

5.?UNCOMMIT

? ? 在Full GC后,如果堆被縮小,就會(huì)出現(xiàn)很多未提交的區(qū)域

6. ALLOC(Old)

????分配的Old區(qū)域,由底的地址確定? ??

7. RETIRE

? ? 在垃圾回收結(jié)束的時(shí)候,最后一個(gè)被分配的Old區(qū)會(huì)被標(biāo)記為退休的

8. REUSE

? ? 下次一GC開(kāi)始時(shí),上一次退休的Old區(qū)會(huì)作為起始點(diǎn)

9. ALLOC(Survivor)

????分配的Survivor區(qū)域,由底的地址確定?? ??

10.?EVAC-FAILURE

? ? 如果分配中出現(xiàn)疏散失敗,這里會(huì)指出失敗的區(qū)域

11.?POST-COMPACTION(Old)

? ? 在Full GC結(jié)束后,對(duì)有存活數(shù)據(jù)的Old和巨型數(shù)據(jù)區(qū)會(huì)進(jìn)行壓縮

12.?ALLOC(SingleH)

????分配SingleH巨型數(shù)據(jù)區(qū)域,對(duì)象只能占用一個(gè)區(qū)域

13.?ALLOC(StartsH)

? ? 分配StartsH巨型數(shù)據(jù)區(qū),對(duì)象可以放置在不止一個(gè)區(qū)域中

14.?ALLOC(ContinuesH)

? ? 分配ContinuesH巨型數(shù)據(jù)區(qū)


?‘-XX:+G1PrintRegionLivenessInfo’ 用于分析并發(fā)標(biāo)記后old區(qū)的分布:



其實(shí)就是翻譯了下這篇文章

Collecting and reading G1 garbage collector logs - part 2

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容