G1垃圾回收

G1垃圾回收.png

G1

調優(yōu)場景

Evacuation Failure

"evacuation failure", "to-space exhausted", "to-space overflow", "promotion failure"之類的字眼。這些術語的概念在G1 GC是相似的

巨型對象和巨型對象分配

對于 G1 GC,任何超過區(qū)域一半大小的對象都被視為“巨型對象”。此類對象直接被分配到老年代中的“巨型區(qū)域”。這些巨型區(qū)域是一個連續(xù)的區(qū)域集。StartsHumongous 標記該連續(xù)集的開始,ContinuesHumongous 標記它的延續(xù)。

在分配任何巨型區(qū)域之前,會檢查標記閾值,如有必要,還會啟動一個并發(fā)周期。

在清理階段或完整的垃圾回收周期內,標記周期結束時會清理死亡的巨型對象。

為了減少復制開銷,巨型對象未包括在疏散暫停中。完整的垃圾回收周期會對巨型對象進行壓縮。

由于每個 StartsHumongous 和 ContinuesHumongous 區(qū)域集只包含一個巨型對象,所以沒有使用巨型對象的終點與上個區(qū)域的終點之間的空間(即巨型對象所跨的空間)。如果對象只是略大于堆區(qū)域大小的倍數(shù),則此類未使用的空間可能會導致堆碎片化。

如果巨型分配導致連續(xù)的并發(fā)周期,并且此類分配導致老年代碎片化,請增加 -XX:G1HeapRegionSize,這樣一來,之前的巨型對象就不再是巨型對象了,而是采用常規(guī)的分配路徑。

當未找到能放下巨型對象的連續(xù)分區(qū)時,G1會首先嘗試擴展堆空間,擴展失敗時,啟動串行gull gc。

引用處理

-XX:PrintReferenceGC在GC日志中輸出各種引用詳細GC數(shù)據。

通常,在G1年輕代或者混合收集中,當PrintGCDetails輸出中的Ref Proc時間超過GC暫停時間總數(shù)的10%時,需要進行調優(yōu):

1.-XX:+ParalleRefProcEnabled激活多線程引用處理,負面影響是會搶占用戶線程時間片。

2.第一點作用不明顯時,觀察GC日志,找到導致Ref Proc處理時間過長的引用類型,優(yōu)化應用程序減少對該類型引用的使用。

軟引用特別說明:

由于軟引用對象只會在OOM前回收,所以軟引用對象可能會長期占用內存而頻繁觸發(fā)老年代收集周期,使用-XX:SoftRefLRUPolicyMSPerMB可以控制軟引用對象回收時機,

回收周期

年輕代GC

對象從eden區(qū)分配失敗時觸發(fā),copy eden + from survivor -> to survivor,超過晉升閾值的對象copy到老年代。

  • -XX:MaxGCPauseMillis 200ms

    JVM會根據該參數(shù)調整年輕代大小。如果用戶設置了-Xmn或者-XX:NewRatio等年輕代空間調整參數(shù),會導致暫停目前參數(shù)失效。

  • -XX:G1NewSizePercent 5%

  • -XX:G1MaxNewSizePercent 60%

  • -XX:MaxTenuringThreshold 15

混合GC

觸發(fā)時機:

當老年代分區(qū)占用總堆比例超過閾值(默認45%)時,觸發(fā)混合GC。

初始標記:和下一次年輕代GC一起,STW并行標記,收集所有的GC Roots。

并發(fā)標記:多線程并發(fā)協(xié)同標示存活對象圖。

重新標記:STW并行重新標記上個階段產生的新垃圾。

并行回收:垃圾清理。

  • -XX:ConGCThreads

    設置并行標記的線程數(shù)。默認值為并行垃圾回收線程數(shù) (ParallelGCThreads) 的 1/4 。

增大該值將會占用應用線程處理時間,降低吞吐量,因為并發(fā)GC線程和應用線程同時工作。

  • 初始標記

    借道年輕代的STW執(zhí)行,標記出GC Roots直接可達的對象,將NTAMS置到分區(qū)頂部。

- -XX:InitiatingHeapOccupancyPercent IHOP 45%

  老年代占用比例超過該值時觸發(fā)并發(fā)標記周期。
  • 根分區(qū)掃描

    年輕代存活對象作為“根分區(qū)”,掃描“根分區(qū)”對老年代的引用。

  • 并發(fā)標記周期

    使用基于寫前柵欄的SATB快照標記算法(應用線程將發(fā)生更改前的引用放入stab_queue,由并發(fā)標記線程定期處理,以此找到標記開始時刻的存活對象快照),在多個并發(fā)標記周期不斷交換PTAMS和NTAMS完成標記。

http://www.itdecent.cn/p/9e70097807ba

  • 重新標記

    STW,GC線程并行處理所有生效的SATB緩沖區(qū)及所有更新(Rset更新?)。處理引用。

  • 清除

    識別所有空閑分區(qū),清理空閑分區(qū)RSet,釋放到空閑隊列;

    整理堆分區(qū),為混合垃圾回收識別出高效率的老年代分區(qū);

    RSet梳理(比如,標記過程發(fā)現(xiàn)RSet中記錄的某個對象已經死亡,將該記錄從RSet中刪除)。

高效率的分區(qū):

1.存活對象少。

2.對象被別的分區(qū)對象引用數(shù)量少。這里數(shù)量多會導致RSet中PRT粒度粗化,增大RSet掃描開銷。

交換位圖、指針?并發(fā)標記周期也交換?

  • 混合回收

    • -XX:G1MixedGCLiveThresholdPercent 85%

      old generation region 中的存活對象的占比,低于該值時才會被選入 CSet。

    • -XX:G1MixedGCCountTarget 8

      設置標記周期完成后,對存活數(shù)據上限為 G1MixedGCLIveThresholdPercent 的舊區(qū)域執(zhí)行混合垃圾回收的目標次數(shù)。默認值是 8 次混合垃圾回收。混合回收的目標是要控制在此目標次數(shù)以內。

  每次混合收集老年代CSet的最小數(shù)量 = 混合收集周期將回收的候選老年代分區(qū)總數(shù)/G1MixedGCCountTarge

  

  

- -XX:G1HeapWastePercent 10%

  混合收集周期中發(fā)現(xiàn)垃圾占總堆比例低于該值時,停止混合收集周期

- -XX:G1OldCSetRegionThresholdPercent 10%

  每次混合收集暫停收集分區(qū)上限,默認總堆的10%

Full GC

觸發(fā)時機:對象分配失敗時?

使用串行垃圾收集器對整個堆全面壓縮。

G1的設計目標通過不斷調優(yōu)而不再需要full GC。

公共

  • -XX:G1HeapRegionSize

    超過該值50%的對象將被視為巨型對象,直接分配在老年代。JDK 8u40之前,巨型對象由混合GC并發(fā)收集周期的清除階段回收,之后可以在年輕代GC回收。

1MB~32MB,G1默認將堆劃為為約2048個Region。

  • -XX:G1ReservePercent=10

    設置作為空閑空間的預留內存百分比,以降低目標空間溢出的風險。默認值是 10%。增加或減少百分比時,請確保對總的 Java 堆調整相同的量。

copy對象到to-space時產生對象晉升,老年代空間不足時會擴展老年代堆空間,老年代空間已達上限會產生晉升失敗,增大預留內存占比可避免晉升失敗。

  • -XX:ParallelGCThreads

    設置 STW 工作線程數(shù)的值。將 n 的值設置為邏輯處理器的數(shù)量。n 的值與邏輯處理器的數(shù)量相同,最多為 8。

如果邏輯處理器不止八個,則將 n 的值設置為邏輯處理器數(shù)的 5/8 左右。這適用于大多數(shù)情況,除非是較大的 SPARC 系統(tǒng),其中 n 的值可以是邏輯處理器數(shù)的 5/16 左右。

堆空間調整

JVM通過在Xms和Xmx之間動態(tài)調整堆大小及年輕代大小,以滿足用戶設置的GC暫停時間MaxGCPauseMillis和GCTimeRatio(用戶線程時間/GC線程時間)的目標。

RSet

引用關系

PRT 粒度?

關系維護

維護時機:

對象引用關系變化時(包括引用賦值、GC移動對象等),觸發(fā)寫柵欄代碼,維護Rset。

若發(fā)生一個跨區(qū)引用關系變化,G1垃圾收集器會將相應的card加入到“臟卡片隊列”?!安l(fā)優(yōu)化線程”會掃描隊列中的卡片來更新RSet。當“并發(fā)優(yōu)化線程”來不及處理不過來時,會掛起用戶線程,讓用戶線程也加入到更新Rset。

全局卡片表

在任意收集周期,掃描Rset與PRT時,會將掃描到的引用記錄標記到全局卡片表,避免重復掃描。在收集周期的最后將該表清空,顯示為Clear CT。

工作竊取機制

收集活動圖

活動流程

關鍵算法

http://www.itdecent.cn/p/548c67aa1bc0

RSET

年輕代收集

如何確保新生代對象被老年代引用的時候不被gc?(查詢老年代對象來確認對新生代對象的引用避免誤回收)

機制:當老年代存活對象多時,每次minor gc查詢老年代所有對象影響gc效率(因為gc stop-the-world),所以在老年代有一個write barrier(寫屏障)來管理的card table(卡表),card table存放了所有老年代對象對新生代對象的引用。

所以每次minor gc通過查詢card table來避免查詢整個老年代,以此來提高gc性能。

初始標記

并發(fā)標記周期

混合收集周期

GC日志

跑出完成GC日志,標記日志說明。

http://www.itdecent.cn/p/ac1ba3479c08

引用

堆外內存回收

http://www.itdecent.cn/p/35cf0f348275

Reference&ReferenceQueue

http://www.itdecent.cn/p/f0da6c1af815

finalize

http://www.itdecent.cn/p/9d2788fffd5f

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

友情鏈接更多精彩內容