序
本文主要研究下JEP 248: Make G1 the Default Garbage Collector
默認(rèn)垃圾收集器
java9廢棄了CMS垃圾收集器,并把G1提升為默認(rèn)垃圾收集器,替代了原來的吞吐優(yōu)先的ParallelOldGC
Region
G1相對(duì)于之前的垃圾收集器最大的不同是引入了Region。G1雖然也是基于分代機(jī)制血久,但是各個(gè)generation的空間不再連續(xù),如下圖:
可以用-XX:G1HeapRegionSize=16m來指定Region Size,注意它必須是2的乘方牌柄,范圍在1MB到32MB之間。目標(biāo)是根據(jù)最小的Java堆大小劃分出約2048 個(gè)區(qū)域.
Min Heap Size | Region Size |
---|---|
heap < 4GB | 1MB |
4GB <= heap < 8GB | 2MB |
8GB <= heap < 16GB | 4MB |
16GB <= heap < 32GB | 8MB |
32GB <= heap < 64GB | 16MB |
64GB <= heap | 32MB |
如果沒有明確指定侧甫,則自動(dòng)根據(jù)Heap Size來指定珊佣,其對(duì)應(yīng)關(guān)系如下:
Min Heap Size | Region Size |
---|---|
heap < 4GB | 1MB |
4GB <= heap < 8GB | 2MB |
8GB <= heap < 16GB | 4MB |
16GB <= heap < 32GB | 8MB |
32GB <= heap < 64GB | 16MB |
64GB <= heap | 32MB |
Humongous Object/ Humongous區(qū)域
- 對(duì)于G1 GC,任何超過區(qū)域一半大小的對(duì)象都被視為“巨型對(duì)象”披粟。
- 此類對(duì)象直接被分配到老年代中的“巨型區(qū)域”咒锻。
- 這些巨型區(qū)域是一個(gè)連續(xù)的區(qū)域集。StartsHumongous 標(biāo)記該連續(xù)集的開始守屉,ContinuesHumongous 標(biāo)記它的延續(xù)惑艇。
巨型對(duì)象默認(rèn)直接會(huì)被分配在年老代,但是如果它是一個(gè)短期存在的巨型對(duì)象,就會(huì)對(duì)垃圾收集器造成負(fù)面影響滨巴。為了解決這個(gè)問題思灌,G1劃分了一個(gè)Humongous區(qū),它用來專門存放巨型對(duì)象恭取。如果一個(gè)H區(qū)裝不下一個(gè)巨型對(duì)象泰偿,那么G1會(huì)尋找連續(xù)的H分區(qū)來存儲(chǔ)。為了能找到連續(xù)的H區(qū)蜈垮,有時(shí)候不得不啟動(dòng)Full GC耗跛。
GC事件及觸發(fā)
GC event
- Minor GC event
正常的young gc
- Mixed GC event
Minor GC + (# reclaimable Tenured regions / -XX:G1MixedGCCountTarget) regions of Tenured
- Full GC event
All regions evacuated,通常Humongous object太多會(huì)耗盡空間攒发,導(dǎo)致Full GC
- Minor/Mixed + To-space exhaustion
Minor/Mixed + rollback + Full GC
觸發(fā)時(shí)機(jī)
- Eden滿/空間不夠
- 剩余空間不夠容納一個(gè)Humongous object
- Humongous object分配成功调塌,同時(shí)符合一些GC條件
- 外部命令觸發(fā)(jcmd, jmap, Runtime.gc())
G1 GC分類
主要分為:Minor GC,Mixed/Old GC
Minor GC/Young GC(STW
)
Young GC主要是對(duì)Eden區(qū)進(jìn)行GC惠猿,它在Eden空間不夠時(shí)會(huì)被觸發(fā)羔砾。Eden空間的數(shù)據(jù)移動(dòng)到Survivor空間中,如果Survivor空間不夠紊扬,Eden空間的部分?jǐn)?shù)據(jù)會(huì)直接晉升到年老代空間蜒茄。From Survivor區(qū)的數(shù)據(jù)移動(dòng)到To Survivor區(qū)中,也有部分?jǐn)?shù)據(jù)晉升到老年代空間中餐屎。
階段 | 執(zhí)行動(dòng)作 |
---|---|
階段1 根掃描 | 靜態(tài)和本地對(duì)象被掃描 |
階段2 更新RS | 處理dirty card隊(duì)列更新RS |
階段3 處理RS | 檢測(cè)從年輕代指向年老代的對(duì)象 |
階段4 對(duì)象拷貝 | 拷貝存活的對(duì)象到survivor/old區(qū)域 |
階段5 處理引用隊(duì)列 | 軟引用檀葛,弱引用,虛引用處理 |
其階段主要如下:
階段 | 執(zhí)行動(dòng)作 |
---|---|
階段1 根掃描 | 靜態(tài)和本地對(duì)象被掃描 |
階段2 更新RS | 處理dirty card隊(duì)列更新RS |
階段3 處理RS | 檢測(cè)從年輕代指向年老代的對(duì)象 |
階段4 對(duì)象拷貝 | 拷貝存活的對(duì)象到survivor/old區(qū)域 |
階段5 處理引用隊(duì)列 | 軟引用腹缩,弱引用屿聋,虛引用處理 |
Mixed/Old GC(STW
)
主要是對(duì)年老代進(jìn)行并發(fā)標(biāo)記然后進(jìn)行GC,其中部分階段涉及到y(tǒng)gc藏鹊,同時(shí)既有ygc及old gc的部分稱為mixed gc润讥。
階段 | 執(zhí)行動(dòng)作 |
---|---|
(1) Initial Mark(Stop the World Event) 初始標(biāo)記階段 | 在此階段G1 GC對(duì)根進(jìn)行標(biāo)記。該階段與常規(guī)的 (STW) 年輕代垃圾回收密切相關(guān)盘寡。日志標(biāo)記為Pause Initial Mark (G1 Evacuation Pause). |
(2) Root Region Scanning 根區(qū)域掃描階段 | G1 GC在初始標(biāo)記的存活區(qū)掃描對(duì)老年代的引用楚殿,并標(biāo)記被引用的對(duì)象。該階段與應(yīng)用程序(非 STW)同時(shí)運(yùn)行竿痰,并且只有完成該階段后脆粥,才能開始下一次STW年輕代垃圾回收。 |
(3) Concurrent Marking 并發(fā)標(biāo)記階段 | G1 GC在整個(gè)堆中查找可訪問的(存活的)對(duì)象影涉。該階段與應(yīng)用程序同時(shí)運(yùn)行变隔,可以被 STW 年輕代垃圾回收中斷。 |
(4) Remark(Stop the World Event) 重新標(biāo)記階段 | 該階段是STW回收蟹倾,幫助完成標(biāo)記周期匣缘。G1 GC清空SATB緩沖區(qū)猖闪,跟蹤未被訪問的存活對(duì)象,并執(zhí)行引用處理肌厨。 |
(5) Copying(Stop the World Event) / Cleanup(Stop the World Event and Concurrent) 拷貝/清理階段 | 在這個(gè)最后階段培慌,G1 GC為了更快進(jìn)行垃圾回收,會(huì)選擇那些存活率低的region進(jìn)行拷貝柑爸,即evacuate或者拷貝存活對(duì)象到新的空閑的regions检柬,然后清理回收該region,此時(shí)會(huì)STW竖配,如果是在年輕代產(chǎn)生的,則日志標(biāo)記為Pause Young (G1 Evacuation Pause)里逆,如果年輕代和年老代都進(jìn)行這個(gè)動(dòng)作进胯,則日志標(biāo)記為Pause Mixed (G1 Evacuation Pause). |
并發(fā)標(biāo)記周期(Concurrent Marking Cycle Phases)階段如下:
階段 | 執(zhí)行動(dòng)作 |
---|---|
(1) Initial Mark(Stop the World Event) 初始標(biāo)記階段 | 在此階段G1 GC對(duì)根進(jìn)行標(biāo)記。該階段與常規(guī)的 (STW) 年輕代垃圾回收密切相關(guān)原押。日志標(biāo)記為Pause Initial Mark (G1 Evacuation Pause). |
(2) Root Region Scanning 根區(qū)域掃描階段 | G1 GC在初始標(biāo)記的存活區(qū)掃描對(duì)老年代的引用胁镐,并標(biāo)記被引用的對(duì)象。該階段與應(yīng)用程序(非 STW)同時(shí)運(yùn)行诸衔,并且只有完成該階段后盯漂,才能開始下一次STW年輕代垃圾回收。 |
(3) Concurrent Marking 并發(fā)標(biāo)記階段 | G1 GC在整個(gè)堆中查找可訪問的(存活的)對(duì)象笨农。該階段與應(yīng)用程序同時(shí)運(yùn)行就缆,可以被 STW 年輕代垃圾回收中斷。 |
(4) Remark(Stop the World Event) 重新標(biāo)記階段 | 該階段是STW回收谒亦,幫助完成標(biāo)記周期竭宰。G1 GC清空SATB緩沖區(qū),跟蹤未被訪問的存活對(duì)象份招,并執(zhí)行引用處理切揭。 |
(5) Copying(Stop the World Event) / Cleanup(Stop the World Event and Concurrent) 拷貝/清理階段 | 在這個(gè)最后階段,G1 GC為了更快進(jìn)行垃圾回收锁摔,會(huì)選擇那些存活率低的region進(jìn)行拷貝廓旬,即evacuate或者拷貝存活對(duì)象到新的空閑的regions,然后清理回收該region谐腰,此時(shí)會(huì)STW孕豹,如果是在年輕代產(chǎn)生的,則日志標(biāo)記為Pause Young (G1 Evacuation Pause)怔蚌,如果年輕代和年老代都進(jìn)行這個(gè)動(dòng)作巩步,則日志標(biāo)記為Pause Mixed (G1 Evacuation Pause). |
核心的階段主要是Concurrent Marking Phase、Remark Phase桦踊、Copying/Cleanup Phase
相關(guān)參數(shù)
參數(shù) | 含義 |
---|---|
-XX:G1HeapRegionSize=n | 設(shè)置Region大小椅野,并非最終值 |
-XX:MaxGCPauseMillis=200 | 設(shè)置G1收集過程目標(biāo)時(shí)間,默認(rèn)值200ms,不是硬性條件 |
-XX:G1NewSizePercent=5 | 新生代最小值竟闪,默認(rèn)值5% |
-XX:G1MaxNewSizePercent=60 | 新生代最大值离福,默認(rèn)值60% |
-XX:ParallelGCThreads=n | STW期間,并行GC線程數(shù)炼蛤,其值與邏輯處理器的數(shù)量相同妖爷,最多為8。如果邏輯處理器不止八個(gè)理朋,則將n為邏輯處理器數(shù)的5/8 |
-XX:ConcGCThreads=n | 并發(fā)標(biāo)記階段的并行標(biāo)記線程數(shù)絮识,ParallelGCThreads的 1/4 左右 |
-XX:InitiatingHeapOccupancyPercent=45 | 設(shè)置觸發(fā)標(biāo)記周期的Java堆占用率閾值。默認(rèn)值是45%嗽上。這里的java堆占比指的是non_young_capacity_bytes次舌,包括old+humongous |
-XX:G1MixedGCLiveThresholdPercent=65 | 為混合垃圾回收周期中要包括的舊區(qū)域設(shè)置占用率閾值。默認(rèn)占用率為 65% |
-XX:G1HeapWastePercent=10 | 如果可回收百分比小于此值兽愤,JVM不會(huì)啟動(dòng)混合垃圾回收周期彼念。默認(rèn)值是10% |
-XX:G1OldCSetRegionThresholdPercent=10 | 設(shè)置混合垃圾回收期間要回收的最大舊區(qū)域數(shù)。默認(rèn)值是Java堆的10% |
-XX:G1MixedGCCountTarget=8 | 設(shè)置標(biāo)記周期完成后浅萧,對(duì)存活數(shù)據(jù)上限為 G1MixedGCLIveThresholdPercent 的舊區(qū)域執(zhí)行混合垃圾回收的目標(biāo)次數(shù)逐沙。默認(rèn)8次混合垃圾回收,混合回收的目標(biāo)是要控制在此目標(biāo)次數(shù)以內(nèi) |
-XX:G1ReservePercent=10 | 設(shè)置作為空閑空間的預(yù)留內(nèi)存百分比洼畅,以降低目標(biāo)空間溢出的風(fēng)險(xiǎn)吩案。默認(rèn)值是10%。增加或減少百分比時(shí)土思,請(qǐng)確保對(duì)總的Java 堆調(diào)整相同的量 |
避免使用-Xmn選項(xiàng)或-XX:NewRatio等其他相關(guān)選項(xiàng)顯式設(shè)置年輕代大小务热,固定年輕代的大小會(huì)禁用掉暫停時(shí)間(MaxGCPauseMillis)目標(biāo)。
GC日志實(shí)例
簡(jiǎn)版使用-Xlog:gc=info己儒,詳細(xì)版使用-Xlog:gc*=info
ygc
- 簡(jiǎn)版
[0.317s][info][gc] GC(37) Pause Young (G1 Evacuation Pause) 7M->6M(10M) 0.511ms
[0.324s][info][gc] GC(40) Pause Young (G1 Evacuation Pause) 7M->6M(10M) 0.709ms
- 詳細(xì)版
[0.011s][info][gc,heap] Heap region size: 1M
[0.012s][info][gc ] Using G1
[0.012s][info][gc,heap,coops] Heap address: 0x00000007bf600000, size: 10 MB, Compressed Oops mode: Zero based, Oop shift amount: 3
[0.170s][info][gc,start ] GC(0) Pause Young (G1 Evacuation Pause)
[0.170s][info][gc,task ] GC(0) Using 8 workers of 8 for evacuation
[0.172s][info][gc,phases ] GC(0) Pre Evacuate Collection Set: 0.0ms
[0.172s][info][gc,phases ] GC(0) Evacuate Collection Set: 1.5ms
[0.172s][info][gc,phases ] GC(0) Post Evacuate Collection Set: 0.1ms
[0.172s][info][gc,phases ] GC(0) Other: 0.1ms
[0.172s][info][gc,heap ] GC(0) Eden regions: 4->0(2)
[0.172s][info][gc,heap ] GC(0) Survivor regions: 0->1(1)
[0.172s][info][gc,heap ] GC(0) Old regions: 0->1
[0.172s][info][gc,heap ] GC(0) Humongous regions: 0->0
[0.172s][info][gc,metaspace ] GC(0) Metaspace: 5982K->5982K(1056768K)
[0.172s][info][gc ] GC(0) Pause Young (G1 Evacuation Pause) 4M->1M(10M) 1.718ms
[0.172s][info][gc,cpu ] GC(0) User=0.01s Sys=0.00s Real=0.00s
old gc
- 簡(jiǎn)版
[0.321s][info][gc] GC(38) Pause Initial Mark (G1 Evacuation Pause) 7M->6M(10M) 0.601ms
[0.321s][info][gc] GC(39) Concurrent Cycle
[0.324s][info][gc] GC(40) Pause Young (G1 Evacuation Pause) 7M->6M(10M) 0.709ms
[0.326s][info][gc] GC(39) Pause Remark 7M->7M(10M) 0.623ms
[0.326s][info][gc] GC(39) Pause Cleanup 7M->7M(10M) 0.104ms
[0.326s][info][gc] GC(39) Concurrent Cycle 5.398ms
[0.327s][info][gc] GC(41) Pause Young (G1 Evacuation Pause) 7M->6M(10M) 0.512ms
[0.331s][info][gc] GC(42) To-space exhausted
[0.331s][info][gc] GC(42) Pause Mixed (G1 Evacuation Pause) 7M->7M(10M) 1.190ms
[0.334s][info][gc] GC(43) Pause Initial Mark (G1 Evacuation Pause) 8M->7M(10M) 0.637ms
[0.334s][info][gc] GC(44) Concurrent Cycle
[0.338s][info][gc] GC(45) Pause Young (G1 Evacuation Pause) 8M->7M(10M) 0.553ms
[0.340s][info][gc] GC(44) Pause Remark 8M->8M(10M) 0.582ms
[0.341s][info][gc] GC(44) Pause Cleanup 8M->8M(10M) 0.100ms
[0.341s][info][gc] GC(44) Concurrent Cycle 6.195ms
- 詳細(xì)版
[0.942s][info][gc,start ] GC(192) Pause Initial Mark (G1 Evacuation Pause)
[0.942s][info][gc,task ] GC(192) Using 8 workers of 8 for evacuation
[0.942s][info][gc,phases ] GC(192) Pre Evacuate Collection Set: 0.0ms
[0.942s][info][gc,phases ] GC(192) Evacuate Collection Set: 0.4ms
[0.942s][info][gc,phases ] GC(192) Post Evacuate Collection Set: 0.0ms
[0.942s][info][gc,phases ] GC(192) Other: 0.0ms
[0.942s][info][gc,heap ] GC(192) Eden regions: 0->0(1)
[0.942s][info][gc,heap ] GC(192) Survivor regions: 0->0(1)
[0.942s][info][gc,heap ] GC(192) Old regions: 10->10
[0.942s][info][gc,heap ] GC(192) Humongous regions: 0->0
[0.942s][info][gc,metaspace ] GC(192) Metaspace: 5993K->5993K(1056768K)
[0.942s][info][gc ] GC(192) Pause Initial Mark (G1 Evacuation Pause) 9M->9M(10M) 0.530ms
[0.942s][info][gc,cpu ] GC(192) User=0.00s Sys=0.00s Real=0.00s
[0.942s][info][gc ] GC(193) Concurrent Cycle
[0.942s][info][gc,marking ] GC(193) Concurrent Clear Claimed Marks
[0.942s][info][gc,marking ] GC(193) Concurrent Clear Claimed Marks 0.004ms
[0.942s][info][gc,marking ] GC(193) Concurrent Scan Root Regions
[0.942s][info][gc,marking ] GC(193) Concurrent Scan Root Regions 0.003ms
[0.942s][info][gc,marking ] GC(193) Concurrent Mark (0.942s)
[0.942s][info][gc,marking ] GC(193) Concurrent Mark From Roots
[0.942s][info][gc,task ] GC(193) Using 2 workers of 2 for marking
[0.942s][info][gc,start ] GC(194) Pause Full (Allocation Failure)
[0.943s][info][gc,phases,start] GC(194) Phase 1: Mark live objects
[0.946s][info][gc,stringtable ] GC(194) Cleaned string and symbol table, strings: 3222 processed, 0 removed, symbols: 25923 processed, 0 removed
[0.946s][info][gc,phases ] GC(194) Phase 1: Mark live objects 3.168ms
[0.946s][info][gc,phases,start] GC(194) Phase 2: Compute new object addresses
[0.946s][info][gc,phases ] GC(194) Phase 2: Compute new object addresses 0.418ms
[0.946s][info][gc,phases,start] GC(194) Phase 3: Adjust pointers
[0.949s][info][gc,phases ] GC(194) Phase 3: Adjust pointers 2.706ms
[0.949s][info][gc,phases,start] GC(194) Phase 4: Move objects
[0.949s][info][gc,phases ] GC(194) Phase 4: Move objects 0.005ms
[0.949s][info][gc,task ] GC(194) Using 8 workers of 8 to rebuild remembered set
[0.951s][info][gc,heap ] GC(194) Eden regions: 0->0(1)
[0.951s][info][gc,heap ] GC(194) Survivor regions: 0->0(1)
[0.951s][info][gc,heap ] GC(194) Old regions: 10->10
[0.951s][info][gc,heap ] GC(194) Humongous regions: 0->0
[0.951s][info][gc,metaspace ] GC(194) Metaspace: 5993K->5993K(1056768K)
[0.951s][info][gc ] GC(194) Pause Full (Allocation Failure) 9M->9M(10M) 8.955ms
[0.951s][info][gc,cpu ] GC(194) User=0.01s Sys=0.00s Real=0.01s
小結(jié)
G1收集器博大精深崎岂,有待進(jìn)一步實(shí)踐進(jìn)行深入理解研究。
doc
- JDK 9 features
- JEP 248: Make G1 the Default Garbage Collector
- JEP 291: Deprecate the Concurrent Mark Sweep (CMS) Garbage Collector
- JEP 278: Additional Tests for Humongous Objects in G1
- Getting Started with the G1 Garbage Collector
- G1GC Fundamentals: Lessons from Taming Garbage Collection
- 垃圾優(yōu)先型垃圾回收器調(diào)優(yōu)
- 深入理解 Java G1 垃圾收集器
- Java 9中的GC調(diào)優(yōu)基礎(chǔ)
- Java Hotspot G1 GC的一些關(guān)鍵技術(shù)
- Garbage First G1收集器 理解和原理分析
- Tuning Java Garbage Collection for Apache Spark Applications