剖析G1(Garbage First)

歡迎關(guān)注筆者的公眾號(hào):【阿飛的博客】,首發(fā)都在這里!!!

Java從JDK7U9開始支持G1(正式發(fā)布),所以,如果要使用G1的話,你的Java版本應(yīng)該是JDK7U9或者更新的版本。不過,強(qiáng)烈建議JDK8才使用G1,而且最好是JDK8的最新版本,因?yàn)樵贘DK7~JDK8最新版本迭代過程中,Java針對G1垃圾回收期做了大量的優(yōu)化工作。

G1垃圾回收器是為多處理器大內(nèi)存的服務(wù)器而設(shè)計(jì)的,它根據(jù)運(yùn)行JVM過程中構(gòu)建的停頓預(yù)測模型(Pause Prediction Model)計(jì)算出來的歷史數(shù)據(jù)來預(yù)測本次收集需要選擇的Region數(shù)量,然后盡可能(不是絕對)滿足GC的停頓時(shí)間,G1期望能讓JVM的GC成為一件簡單的事情。G1旨在延遲性和吞吐量之間取得最佳的平衡,它嘗試解決有如下問題的Java應(yīng)用:

  1. 堆大小能達(dá)到幾十G甚至更大,超過50%的堆空間都是存活的對象;
  2. 對象分配和晉升的速度隨著時(shí)間的推移有很大的影響;
  3. 堆上嚴(yán)重的碎片化問題;
  4. 可預(yù)測的停頓時(shí)間,避免長時(shí)間的停頓。

  • 開啟G1

介紹G1之前先簡單的說一下如何開啟G1,在JDK9之前,JDK7和JDK8默認(rèn)都是ParallelGC垃圾回收。到了JDK9,G1才是默認(rèn)的垃圾回收器。所以如果JDK7或者JDK8需要使用G1的話,需要通過參數(shù)(-XX:+UseG1GC)顯示執(zhí)行垃圾回收器。而JDK9以后的版本,不需要任何JVM參數(shù),默認(rèn)就是G1垃圾回收模式,顯示指定G1運(yùn)行一個(gè)Demo程序如下:

java -Xmx1g -Xms1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar demo.jar
  • G1堆

G1的堆結(jié)構(gòu),是Java發(fā)展這么多年,第一次發(fā)生這么大的變化。以前,無論是使用SerialGC,ParallelGC,還是CMS,堆的年輕代和老年代都是連續(xù)的,且堆結(jié)構(gòu)圖都是如下所示:


以前GC的堆

而G1的堆是基于Region設(shè)計(jì)的,事實(shí)上,這些Region本質(zhì)上就是Eden、Survivor和Old,而且同類型的Region可以不連續(xù)。如下圖所示:

G1 Heap Allocation

圖片中不同的顏色表示不同的Region,Region被設(shè)計(jì)為在停止所有其他應(yīng)用程序線程的情況下并行收集,即是STW的。

另外,除了圖中3種常見的Region類型,還有第四種特殊的Region,即:Humongous,它是特殊的老年代Region。這種Region被設(shè)計(jì)用來保存超過Region的50%空間的對象,它們存儲(chǔ)在一系列連續(xù)的Region中。通常來說,超大對象只會(huì)在最終標(biāo)記結(jié)束后的清理階段(cleanup)才會(huì)被回收,或者發(fā)生FullGC時(shí)。但是在JDK8U40的時(shí)候,JDK更新了一些收集超大對象的特性,以至于在YGC的時(shí)候,G1也能回收那些沒有任何引用指向的超大對象,可以通過參數(shù)-XX:+G1ReclaimDeadHumongousObjectsAtYoungGC控制,這個(gè)參數(shù)后來被更名為-XX:+G1EagerReclaimHumongousObjects,并且可以通過參數(shù)-XX:+G1TraceEagerReclaimHumongousObjects跟蹤并輸出超大對象回收相關(guān)信息。

超大對象的分配可能導(dǎo)致過早的發(fā)生垃圾回收,每一個(gè)超大對象分配時(shí),G1會(huì)檢查初始堆占用閾值-XX:InitiatingHeapOccupancyPercent,如果占用比例超過了閾值,那么就會(huì)觸發(fā)全局并發(fā)標(biāo)記。如果超大對象的分配導(dǎo)致連續(xù)發(fā)生全局并發(fā)標(biāo)記,那么請考慮適當(dāng)增加參數(shù) -XX:G1HeapRegionSize 的值,這樣一來,之前的超大對象就不再是超大對象,而是采用常規(guī)的分配方式的普通對象。另外,超大對象的分配還會(huì)導(dǎo)致老年代碎片化,需要注意。

超大對象從來不會(huì)被移動(dòng)(但是可以被清理),即使發(fā)生的是FullGC。這可能會(huì)導(dǎo)致過早的FullGC或者一些意料之外的OOM,而事實(shí)上還有很多可用堆空間。

JVM啟動(dòng)的時(shí)候就會(huì)自動(dòng)設(shè)置Region大小,當(dāng)然,你也可以自己指定Region的大小(例如-XX:G1HeapRegionSize=4m)。Region數(shù)量最多不會(huì)超過2048個(gè),每個(gè)Region的大小在1~32M之間,且必須是2的N次方。這就意味著,如果堆內(nèi)存少于2048M(2G),那么Region數(shù)量就會(huì)少于2048個(gè)。

以前GC的垃圾收集主要分為年輕代的垃圾收集和老年代的垃圾收集,G1這點(diǎn)類似,主要分為年輕代的垃圾收集,即YGC;以及混合收集,即Mixed GC。接下來,我們深入了解一下G1的這兩種垃圾收集。

事實(shí)上,G1和CMS還有一個(gè)相同點(diǎn),在并發(fā)模式GC搞不定的時(shí)候,也會(huì)發(fā)生FullGC,即整個(gè)過程完全STW。

Young GC

G1的YGC回收前是這樣的,當(dāng)Eden滿了后,就會(huì)觸發(fā)YGC,這一點(diǎn)和以前的ParallelGC以及CMS+ParNew是一樣的:


G1年輕代

G1的YGC要做的事情如下圖所示,年輕代存活的對象會(huì)被從多個(gè)Region(Eden)中拷貝并移動(dòng)到1個(gè)或多個(gè)Region(S區(qū)),這個(gè)過程就叫做Evacuation。如果某些對象的年齡值達(dá)到了閾值,就會(huì)晉升到Old區(qū),這一點(diǎn)和以前的GC類似:

YGC Of G1

G1的YGC也是一個(gè)完全STW,且多線程并行執(zhí)行的階段,對應(yīng)的日志如下所示:

[GC pause (G1 Evacuation Pause) (young) 898M->450M(1024M), 0.0005367 secs]

并且為了下一次YGC,Eden和Survivor的大小會(huì)被重新計(jì)算,計(jì)算過程中用戶設(shè)置的停頓時(shí)間目標(biāo)也會(huì)被考慮進(jìn)去,如果需要的話,它們的大小可能調(diào)大,也可能調(diào)小。

存活的對象被拷貝并移動(dòng)到Survivor或者晉升到Old區(qū)(如果有滿足條件的對象的話):


End YGC Of G1

最后對G1的YGC做一個(gè)簡單的總結(jié):

  • 堆是一個(gè)被劃分為多個(gè)Region的單獨(dú)的內(nèi)存空間;
  • 年輕代的內(nèi)存由多個(gè)不連續(xù)的Region組成,這樣的設(shè)計(jì)在需要對年輕代大小擴(kuò)容的時(shí)候,變得更容易;
  • G1的YGC是完全STW的,所有的應(yīng)用線程都需要停止工作;
  • YGC是多線程并行的;
  • 存活的對象會(huì)被拷貝到新的Survivor或者Old類型的Region中;

并發(fā)標(biāo)記周期

全局并發(fā)標(biāo)記周期,即concurrent marking cycle,G1的全局并發(fā)標(biāo)記周期和CMS的并發(fā)收集過程非常相似。不過,G1模式下滿足觸發(fā)全局并發(fā)標(biāo)記的條件由參數(shù)(-XX:InitiatingHeapOccupancyPercent=45)控制,這個(gè)比例是整個(gè)Java堆占用百分比閾值,即Java堆占用這么多空間后,就會(huì)進(jìn)入初始化標(biāo)記->并發(fā)標(biāo)記->最終標(biāo)記->清理的生命周期。而CMS是由參數(shù)(-XX:CMSInitiatingOccupancyFraction)控制,這個(gè)比例是老年代占用比閾值

G1的GC日志樣例參考如下:

[GC pause (G1 Evacuation Pause) (young) (initial-mark) 857M->617M(1024M), 0.0112237 secs]
[GC concurrent-root-region-scan-start]
[GC concurrent-root-region-scan-end, 0.0000525 secs]
[GC concurrent-mark-start]
[GC concurrent-mark-end, 0.0083864 secs]
[GC remark, 0.0038066 secs]
[GC cleanup 680M->680M(1024M), 0.0006165 secs]
[GC pause (G1 Evacuation Pause) (young) 869M->665M(1024M), 0.0084004 secs]
[GC pause (G1 Evacuation Pause) (mixed) 677M->667M(1024M), 0.0136266 secs]
[GC pause (G1 Evacuation Pause) (mixed) 711M->675M(1024M), 0.0101436 secs]
[GC pause (G1 Evacuation Pause) (mixed) 715M->682M(1024M), 0.0114279 secs]
... ...

由日志可知,G1的并發(fā)標(biāo)記周期主要包括如下幾個(gè)過程:

  • 初始化標(biāo)記

STW階段,在G1中,初始化標(biāo)記是伴隨一次普通的YGC發(fā)生的,這么做的好處是沒有額外的、單獨(dú)的暫停階段,這個(gè)階段主要是找出所有的根Region集合。
GC日志中有(young) (initial-mark)字樣:

Initial Mark

  • 根分區(qū)掃描

并發(fā)階段,掃描那些根分區(qū)(Region)集合--Oracle官方介紹的根分區(qū)集合是那些對老年代有引用的Survivor分區(qū),標(biāo)記所有從根集合可直接到達(dá)的對象并將它們的字段壓入掃描棧(marking stack)中等到后續(xù)掃描。G1使用外部的bitmap來記錄mark信息,而不使用對象頭的mark word里的mark bit(JDK12的Shenandoah GC是使用對象頭)。這個(gè)過程是和應(yīng)用線程一起運(yùn)行的,另外需要注意的是,這個(gè)階段必須在下一次YGC發(fā)生之前完成,如果掃描過程中,Eden區(qū)耗盡,那么一定要等待根分區(qū)掃描完成還能進(jìn)行YGC。

  • 并發(fā)標(biāo)記

并發(fā)階段,繼續(xù)掃描,不斷從上一個(gè)階段的掃描棧中取出引用遞歸掃描整個(gè)堆所有存活的對象圖。每掃描到一個(gè)對象就會(huì)對其標(biāo)記,并將其字段壓入掃描棧。重復(fù)掃描過程,直到掃描棧清空。另外,需要注意的是,這個(gè)階段可以被YGC中斷。

Concurrent Mark

  • 最終標(biāo)記

STW階段,徹底完成堆中存活對象的標(biāo)記工作,使用的是SATB(snapshot-at-the-beginning)算法,它比CMS使用的算法更快。因?yàn)椋珿1這個(gè)remark與CMS的remark有一個(gè)本質(zhì)上的區(qū)別,那就是這個(gè)暫停只需要掃描SATB buffer,而CMS的remark需要重新掃描mod-union table里的dirty card外加整個(gè)根集合(這時(shí)候年輕代也是根集合的一部分),而此時(shí)整個(gè)年輕代(不管對象死活)都會(huì)被當(dāng)作根集合的一部分,因而CMS remark有可能會(huì)非常慢(所以,很多CMS優(yōu)化建議配置參數(shù):-XX:+CMSScavengeBeforeRemark,即在最終標(biāo)記之前執(zhí)行一次YGC,減輕最終標(biāo)記的壓力)。

Rmark

  • 清理階段

STW階段。這個(gè)過程主要是從bitmap里統(tǒng)計(jì)每個(gè)Region被標(biāo)記為存活的對象,計(jì)算存活對象的統(tǒng)計(jì)信息,然后將它們按照存活狀況(liveness)進(jìn)行排列。并且會(huì)找出完全空閑的Region,然后回收掉這些完全空閑的Region,并將空間返回到可分配Region集合中。需要說明的是,這個(gè)階段不會(huì)有拷貝動(dòng)作,因?yàn)椴恍枰謇黼A段只回收完全空閑的Region而已,還有存活對象的Region,需要接下來的Mixed GC才能回收。

上面提到的這幾個(gè)過程就是并發(fā)標(biāo)記周期的全過程:初始化標(biāo)記(initial mark)、根分區(qū)掃描(Root region scanning)、并發(fā)標(biāo)記(concurrent marking)、最終標(biāo)記(remark)、清理階段(cleanup)。

  • Evacuation

STW階段,這個(gè)階段會(huì)把存活的對象拷貝到全新的還未使用的Region中,G1的這個(gè)過程有兩種選定CSet的模式。既可能由YGC來完成,只回收年輕代(GC日志樣例:[GC pause (young)])。也可能是Mixed GC來完成的,即回收年輕代又回收(部分)老年代(GC日志樣例:[GC Pause (mixed)])。

Mixed GC

如下圖所示,就是Mixed GC示意圖,回收所有Young區(qū)和部分Old區(qū):

Before Mixed GC

被選中的Region(所有年輕代Region和部分老年代Region)已經(jīng)被回收,存活的對象被壓縮到深藍(lán)色Region(最近被拷貝的老年代Region)和深綠色Region(最近被拷貝的年輕代Region)中:


After Mixed GC

Mixed GC日志如下所示:

[GC pause (G1 Evacuation Pause) (mixed) 715M->682M(1024M), 0.0114279 secs]

Mixed GC是完全STW的,它是G1一種非常重要的回收方式,它根據(jù)用戶設(shè)置的停頓時(shí)間目標(biāo),可以選擇回收所有年輕代,以及部分老年代Region集合(Collection Set,收集集合,簡稱CSet,)。在一次完整的全局并發(fā)標(biāo)記周期后,如果滿足觸發(fā)Mixed GC的條件,那么就會(huì)執(zhí)行Mixed GC,并且Mixed GC可能會(huì)執(zhí)行多次(由上面的GC日志可知,并且最大次數(shù)由參數(shù)-XX:G1MixedGCCountTarget=8控制),直到CSet都被回收,并且盡可能達(dá)到用戶期望的停頓時(shí)間目標(biāo)。

在選定CSet后,G1在執(zhí)行Evacuation階段時(shí),其實(shí)就跟ParallelScavenge的YGC的算法類似,采用并行復(fù)制(或者叫scavenging)算法把CSet里每個(gè)Region中的存活對象拷貝到新的Region里,然后回收掉這些Region,整個(gè)過程完全STW。

G1總結(jié)

前面提到了G1模式下Evacuation階段有兩種選定CSet的子模式,分別對應(yīng)Young GC與Mixed GC:

  • Young GC:選定所有年輕代里的Region。G1是通過調(diào)整年輕代Region數(shù)量來控制YGC的開銷
  • Mixed GC:選定所有年輕代里的Region,外加根據(jù)global concurrent marking統(tǒng)計(jì)得出收集收益高的部分老年代Region,在用戶指定的停頓時(shí)間目標(biāo)范圍內(nèi)盡可能選擇收益高的老年代Region回收,G1就是通過控制回收老年代Region數(shù)量來控制Mixed GC的開銷的。

我們可以看到年輕代Region總是在CSet內(nèi)。因此G1不需要維護(hù)從年輕代Region出發(fā)的引用涉及的RSet更新。 G1的正常工作流程就是在YGC與Mixed GC之間視情況切換,大部分是YGC,Mixed GC次數(shù)少很多,背后定期做全局并發(fā)標(biāo)記(滿足參數(shù)-XX:InitiatingHeapOccupancyPercent條件時(shí))。當(dāng)并發(fā)標(biāo)記周期正在工作時(shí),G1不會(huì)選擇做Mixed GC,反之,如果有Mixed GC正在進(jìn)行,G1也不會(huì)啟動(dòng)并發(fā)標(biāo)記周期(從initial marking開始)。

  • G1模式下的FullGC

在G1的正常工作流程中沒有Full GC的概念,老年代的收集全靠Mixed GC來完成。

但是,畢竟Mixed GC有搞不定的時(shí)候,如果Mixed GC實(shí)在無法跟上程序分配內(nèi)存的速度,導(dǎo)致老年代填滿無法繼續(xù)進(jìn)行Mixed GC,就會(huì)切換到G1之外的Serial Old GC來收集整個(gè)堆(包括Young、Old、Metaspace),這才是真正的Full GC(Full GC不在G1的控制范圍內(nèi)),進(jìn)入這種狀態(tài)的G1就跟-XX:+UseSerialGC的Full GC一樣(背后的核心代碼是兩者共用的)。

這就是為什么不建議G1模式下參數(shù)-XX:MaxGCPauseMillis=200 的值設(shè)置太小,如果設(shè)置太小,可能導(dǎo)致每次Mixed GC只能回收很小一部分Region,最終可能無法跟上程序分配內(nèi)存的速度,從而觸發(fā)Full GC。

順帶一提,G1模式下的System.gc()默認(rèn)還是Full GC,也就是Serial Old GC。只有加上參數(shù) -XX:+ExplicitGCInvokesConcurrent 時(shí)G1才會(huì)用自身的并發(fā)GC來執(zhí)行System.gc();

說明:JDK10已經(jīng)將G1的Full GC優(yōu)化為Parallel模式。可以參考JEP 307: Parallel Full GC for G1:https://openjdk.java.net/jeps/307

比較其他GC

接下來總結(jié)一下G1和另外兩個(gè)使用最多的GC的不同點(diǎn):

  • Parallel GC

為吞吐量而生的垃圾回收器,Parallel GC 只能把老年代的空間當(dāng)作一個(gè)整體來壓縮和回收,且整個(gè)過程完全STW。而G1把這些工作分為幾個(gè)耗時(shí)更短的收集過程,且部分階段是并發(fā)的,而且可以只回收老年代的部分Region,這樣能縮短停頓時(shí)間,但是可能會(huì)犧牲吞吐量。

  • CMS

G1出來之前,低延遲場景下最好的也是最難控制垃圾回收器。G1和CMS類似,G1并發(fā)執(zhí)行部分老年代的回收工作,但是CMS不能解決Old區(qū)的碎片化問題,導(dǎo)致一定會(huì)出現(xiàn)長時(shí)間停頓的FullGC。G1也有碎片化問題,但是比起CMS好很多,另外G1也會(huì)有FullGC,但是頻率遠(yuǎn)沒有CMS那么高。

一些建議

接下來要介紹的是使用G1的最佳實(shí)踐,如果沒有充分的壓測數(shù)據(jù),不建議違背這些建議:

  1. 年輕代大小:也就是說,如果配置了-XX:+UseG1GC,那么盡量避免配置-Xmn(或 -XX:NewRatio 等其他相關(guān)選項(xiàng)顯式設(shè)置年輕代大小)。如果設(shè)置該參數(shù),G1將不能在需要的時(shí)候調(diào)整年輕代的大小,也不能根據(jù)設(shè)置的暫停時(shí)間調(diào)整收集策略。換句話說,如果配置了-Xmn,也就關(guān)閉了參數(shù)-XX:MaxGCPauseMillis=200設(shè)定的停頓目標(biāo),具體YGC的停頓時(shí)間,那就完全由-Xmn直接決定了。
  2. 響應(yīng)時(shí)間:不要使用平均響應(yīng)時(shí)間作為設(shè)置參數(shù)-XX:MaxGCPauseMillis=200的衡量標(biāo)準(zhǔn),而應(yīng)該根據(jù)90%(或者更高比例)響應(yīng)時(shí)間來設(shè)置這個(gè)參數(shù)。需要強(qiáng)調(diào)的是,這個(gè)參數(shù)設(shè)定的只是一個(gè)目標(biāo),而不是一定達(dá)到的保證。
  3. CMS or G1,什么時(shí)候選擇CMS,什么時(shí)候選擇G1?這是一個(gè)偽命題。其實(shí)CMS在較小的堆、合適的workload的條件下暫停時(shí)間可以很輕松的短于G1。以JDK8高版本為例(JDK7到JDK8,G1的實(shí)現(xiàn)經(jīng)過了很多的優(yōu)化),大概在6GB~8GB也可以跟CMS有一比,我之前見過有在-Xmx4g的環(huán)境里G1比CMS的暫停時(shí)間更短的個(gè)案。總之,G1更適合大堆,比如20G,30G,50G,不要猶豫選擇G1吧。而對于4G,8G這種中小堆,如果謹(jǐn)慎的話,建議壓測后再?zèng)Q定。否則CMS也是一個(gè)保(不)守(錯(cuò))的選擇。

需要說明的是,這里只是建議,而不是絕對。畢竟每個(gè)應(yīng)用的特性,以及運(yùn)行的環(huán)境千差萬別。Java官方是不建議顯示設(shè)置年輕代大小的,但是筆者一些朋友遇到這樣的問題:默認(rèn)目標(biāo)停頓時(shí)間200ms,且堆非常大的情況下,Eden區(qū)非常小,Young區(qū)也非常小。下面就是一段這樣的GC日志,我們可以看到整個(gè)堆是(約等于)7G,但是Eden區(qū)只有300多M。為什么G1把這個(gè)Eden區(qū)大小調(diào)的這么小呢?我們再看一下停頓時(shí)間,這一次YGC耗時(shí)190ms,非常接近目標(biāo)停頓時(shí)間。如果G1再調(diào)大Eden區(qū)大小,那么YGC時(shí)停頓時(shí)間就非常可能超過200ms:

[Eden: 350.0M(350.0M)->0.0B(306.0M) Survivors: 0.0B->44.0M Heap: 410.1M(7000.0M)->135.2M(7000.0M)]
 [Times: user=0.60 sys=0.15, real=0.19 secs]

附:G1的JVM參數(shù)

接下來列舉G1模式下一些重要的參數(shù)和它們的默認(rèn)值,以及這些參數(shù)的含義。

參數(shù)及默認(rèn)值 描述信息
-XX:MaxGCPauseMillis=200 期望的最大停頓時(shí)間。千萬不要對這個(gè)參數(shù)有誤解,認(rèn)為設(shè)置它為10,就能控制每次停頓時(shí)間都不會(huì)10ms。這種極端的設(shè)置只會(huì)適得其反,導(dǎo)致每次Mixed GC只能回收很少一部分區(qū)域,從而讓情況不斷惡化,發(fā)生FullGC的概率大大提高
-XX:G1HeapRegionSize=ergo 堆的Region的大小,整個(gè)堆最多劃分為2048個(gè)Region,Region的大小一定是在1~32M之間,并且是2的N次方。 所以,如果堆的尺寸小于2G,那么Region數(shù)量就會(huì)少于2048
-XX:GCPauseTimeInterval=ergo 最大停頓時(shí)間間隔的目標(biāo),G1默認(rèn)沒有設(shè)置這個(gè)目標(biāo),允許G1在一些極端的情況下連續(xù)執(zhí)行垃圾回收
-XX:ParallelGCThreads=ergo 并行階段最大的線程數(shù),JVM根據(jù)CPU核心數(shù)N進(jìn)行計(jì)算,如果N<8,那么ParallelGCThreads=N;如果N>=8,那么ParallelGCThreads=N*5/8
-XX:ConcGCThreads=ergo 并發(fā)階段最大的線程數(shù),默認(rèn)值是-XX:ParallelGCThreads的值除以4
-XX:+G1UseAdaptiveIHOP G1是否使用自適應(yīng)初始化堆占用百分比
-XX:InitiatingHeapOccupancyPercent=45 設(shè)置觸發(fā)全局并發(fā)標(biāo)記周期的整個(gè)Java堆占用百分比閾值,即Java堆占用這么多空間后,就會(huì)進(jìn)入初始化標(biāo)記->并發(fā)標(biāo)記->重新標(biāo)記->清理的生命周期
-XX:G1NewSizePercent=5 表示年輕代占用堆大小的最小百分比,還有另一個(gè)參數(shù)-XX:G1MaxNewSizePercent=60,表示年輕代占用堆大小的最大百分比,JVM會(huì)在這兩個(gè)百分比之間變化
-XX:G1HeapWastePercent=5 設(shè)置你允許浪費(fèi)的堆的百分比,如果可回收百分比低于這個(gè)百分比,那么G1就不會(huì)觸發(fā)Mixed GC。
-XX:G1MixedGCLiveThresholdPercent=85 如果老年代Region中存活對象超過這個(gè)比例,不會(huì)被選入CSet,Mixed GC也就不會(huì)回收這個(gè)Region。因?yàn)榇婊顚ο筇啵厥諆r(jià)值不大
-XX:G1MixedGCCountTarget=8 全局并發(fā)標(biāo)記周期后,對存活對象上限為G1MixedGCLiveThresholdPercent的老年代Region執(zhí)行Mixed GC的次數(shù)上限,默認(rèn)值是8次,即最多不能超過8次Mixed GC
-XX:G1ReservePercent=10 設(shè)置作為空閑空間的預(yù)留內(nèi)存百分比,以減少晉升失敗、降低堆空間溢出的風(fēng)險(xiǎn)。默認(rèn)值是10%。增加或減少百分比時(shí),請確保對總的Java堆調(diào)整相同的量。
-XX:G1OldCSetRegionThresholdPercent=10 設(shè)置Mixed GC期間要回收的老年代Region數(shù)量上限,即一次Mixed GC中最多可以被選入CSet中的老年代Region數(shù)量。默認(rèn)值是Java堆的10%。

備注:值為ergo意味著其具體值與環(huán)境有關(guān)。


  • 參考鏈接

[參考鏈接1]:https://hllvm-group.iteye.com/group/topic/44381
[參考鏈接2]:https://tech.meituan.com/2016/09/23/g1.html
[參考鏈接3]:https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html

我的微信公眾號(hào)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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