<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          深(淺)入(出)剖析G1(Garbage First)

          共 11358字,需瀏覽 23分鐘

           ·

          2021-03-16 12:20

          Java從JDK7U9開始支持G1(正式發(fā)布),所以,如果要使用G1的話,你的Java版本應(yīng)該是JDK7U9或者更新的版本。不過,強(qiáng)烈建議JDK8才使用G1,而且最好是JDK8的最新版本,因?yàn)樵贘DK7~JDK8最新版本迭代過程中,Java針對(duì)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ù)量,然后盡可能(不是絕對(duì))滿足GC的停頓時(shí)間,G1期望能讓JVM的GC成為一件簡單的事情。G1旨在延遲性和吞吐量之間取得最佳的平衡,它嘗試解決有如下問題的Java應(yīng)用:

          1. 堆大小能達(dá)到幾十G甚至更大,超過50%的堆空間都是存活的對(duì)象;

          2. 對(duì)象分配和晉升的速度隨著時(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%空間的對(duì)象,它們存儲(chǔ)在一系列連續(xù)的Region中。通常來說,超大對(duì)象只會(huì)在最終標(biāo)記結(jié)束后的清理階段(cleanup)才會(huì)被回收,或者發(fā)生FullGC時(shí)。但是在JDK8U40的時(shí)候,JDK更新了一些收集超大對(duì)象的特性,以至于在YGC的時(shí)候,G1也能回收那些沒有任何引用指向的超大對(duì)象,可以通過參數(shù)-XX:+G1ReclaimDeadHumongousObjectsAtYoungGC控制,這個(gè)參數(shù)后來被更名為-XX:+G1EagerReclaimHumongousObjects,并且可以通過參數(shù)-XX:+G1TraceEagerReclaimHumongousObjects跟蹤并輸出超大對(duì)象回收相關(guān)信息。

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

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

          YGC Of G1

          G1的YGC也是一個(gè)完全STW的過程,且多線程并行執(zhí)行的階段,對(duì)應(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)小。

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

          End YGC Of G1

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

          • 堆是一個(gè)被劃分為多個(gè)Region的單獨(dú)的內(nèi)存空間;

          • 年輕代的內(nèi)存由多個(gè)不連續(xù)的Region組成,這樣的設(shè)計(jì)在需要對(duì)年輕代大小擴(kuò)容的時(shí)候,變得更容易;

          • G1的YGC是完全STW的,所有的應(yīng)用線程都需要停止工作;

          • YGC是多線程并行的;

          • 存活的對(duì)象會(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并發(fā)標(biāo)記周期階段的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]

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

          • 初始化標(biāo)記

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

          Initial Mark
          • 根分區(qū)掃描

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

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

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

          [GC pause (G1 Evacuation Pause) (young) (initial-mark) 963M->962M(1024M), 0.0070962 secs]
          [GC concurrent-root-region-scan-start]
          [GC concurrent-root-region-scan-end, 0.0000394 secs]
          [GC concurrent-mark-start]
          [GC pause (G1 Evacuation Pause) (young)-- 1004M->1006M(1024M), 0.0020180 secs]
          [GC pause (G1 Evacuation Pause) (young)-- 1024M->1024M(1024M), 0.0005811 secs]


          • 最終標(biāo)記

          STW階段,徹底完成堆中存活對(duì)象的標(biāo)記工作,使用的是SATB算法,它比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è)年輕代(不管對(duì)象死活)都會(huì)被當(dāng)作根集合的一部分,因而CMS remark有可能會(huì)非常慢(所以,很多CMS優(yōu)化建議配置參數(shù):-XX:+CMSScavengeBeforeRemark,即在最終標(biāo)記之前執(zhí)行一次YGC,減輕最終標(biāo)記的壓力)。

          Rmark

          SATB,即snapshot-at-the-beginning,抽象的說就是在一次GC開始的時(shí)候,是活的對(duì)象就被認(rèn)為一直是活的,直到這個(gè)GC完成,此時(shí)堆中所有的對(duì)象形成一個(gè)邏輯“快照”(snapshot),另外在GC過程中新分配的對(duì)象都當(dāng)作是活的,其它不可到達(dá)的對(duì)象就是死的了。

          • 清理階段

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

          上面提到的這幾個(gè)過程就是全局并發(fā)標(biāo)記周期的全過程:初始化標(biāo)記(initial mark)、根分區(qū)掃描(Root region scanning)、并發(fā)標(biāo)記(concurrent marking)、最終標(biāo)記(remark)、清理階段(cleanup)。全局并發(fā)標(biāo)記的目的就是為了讓G1的Mixed GC可以找出適合的老年代Region來收集,必須在老年代變得無法擴(kuò)張(也就基本無法收集)之前完成標(biāo)記。

          • Evacuation

          STW階段,這個(gè)階段會(huì)把存活的對(duì)象拷貝到全新的還未使用的Region中,G1的這個(gè)階段的CSet可以有任意多個(gè)Region,CSet的選擇,完全根據(jù)停頓預(yù)測模型找出收益盡可能高、開銷盡可能小的這類Region。G1的這個(gè)過程有兩種選定CSet的模式:既可能由YGC來完成,只回收所有的年輕代(GC日志樣例:[GC pause (young)])。也可能是Mixed GC來完成的,即回收所有的年輕代以及部分老年代(GC日志樣例:[GC Pause (mixed)]):

          第一段GC日志--并發(fā)標(biāo)記周期后先YGC然后Mixed GC:
          [GC remark, 0.0021950 secs]
          [GC cleanup 809M->351M(1024M), 0.0009678 secs]
          [GC concurrent-cleanup-start]
          [GC concurrent-cleanup-end, 0.0001810 secs]
          [GC pause (G1 Evacuation Pause) (young) 380M->380M(1024M), 0.0119252 secs]
          [GC pause (G1 Evacuation Pause) (mixed) 416M->406M(1024M), 0.0072944 secs]

          第二段GC日志--并發(fā)標(biāo)記周期后只有YGC:
          [GC cleanup 763M->279M(1024M), 0.0013693 secs]
          [GC concurrent-cleanup-start]
          [GC concurrent-cleanup-end, 0.0001920 secs]
          [GC pause (G1 Evacuation Pause) (young) 347M->346M(1024M), 0.0178034 secs]
          [GC pause (G1 Evacuation Pause) (young) 462M->462M(1024M), 0.0346993 secs]
          [GC pause (G1 Evacuation Pause) (young) 602M->602M(1024M), 0.0301031 secs]
          [GC pause (G1 Evacuation Pause) (young) (initial-mark) 760M->760M(1024M), 0.1005118 secs]
          [GC concurrent-root-region-scan-start]

          網(wǎng)上很多文章介紹:初始化標(biāo)記->根區(qū)域掃描->并發(fā)標(biāo)記->最終標(biāo)記->清理這幾個(gè)階段就是Mixed GC的一部分,這種說法是錯(cuò)誤的。這幾個(gè)階段只是G1的并發(fā)標(biāo)記周期,它是為Mixed GC選取多少個(gè)老年代Region服務(wù)的,至于接下來是發(fā)生YGC還是Mixed GC,都是有可能的,上面的GC日志樣例就能驗(yàn)證這個(gè)說法。

          Mixed GC

          如下圖所示,就是Mixed GC示意圖,回收所有年輕代Region和部分老年代Region:

          Before Mixed GC

          被選中的Region(所有年輕代Region和部分老年代Region)已經(jīng)被回收,存活的對(duì)象被壓縮到深藍(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)。

          # 全局并發(fā)標(biāo)記周期 start
          [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]
          # 全局并發(fā)標(biāo)記周期 end

          # mixed gc start,連續(xù)幾次mixed gc
          [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]
          ... ...

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

          G1總結(jié)

          G1模式下Evacuation階段有兩種選定CSet的子模式,分別對(duì)應(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的開銷的。

          我們可以看到無論發(fā)生的是YGC還是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í),G1的并發(fā)動(dòng)作只出現(xiàn)在全局并發(fā)標(biāo)記周期,YGC和Mixed GC都是完全STW的)。當(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模式??梢詤⒖糐EP 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. 停頓時(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á)到的保證。不建議將這個(gè)參數(shù)設(shè)置的過低,例如100ms以內(nèi),除非針對(duì)你的應(yīng)用,有充分的壓測數(shù)據(jù)佐證你的設(shè)置。

          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吧。而對(duì)于4G,8G這種中小堆,如果謹(jǐn)慎的話,建議壓測后再?zèng)Q定。否則CMS也是一個(gè)保(不)守(錯(cuò))的選擇。

          需要說明的是,這里只是建議,而不是絕對(duì)。畢竟每個(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)的這么小呢?我們?cè)倏匆幌峦nD時(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ù)的含義:


          瀏覽 145
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  人人舔人人操人人射 | 日韩一级精品 | 99视频在线观看6 | 美女视频A片 | 操屄视频在线免费观看 |