1. 程式人生 > >java虛擬機器面試乾貨【拾】_G1 GC的回收機制

java虛擬機器面試乾貨【拾】_G1 GC的回收機制

簡單來說,G1 GC的收集分為4個階段:年輕代GC,併發標記週期,混合回收和full GC。

年輕代GC

G1 GC的年輕代回收基本沿襲了之前的設計,通過複製演算法和一個Eden區、兩個Survivor區實現。但區別在於,大物件的分配是可以直接到大物件區間的(詳見上文)。此外,在每一次年輕代回收暫停期間,G1 GC會計算當前年輕代大小需要擴充套件或者壓縮的總量,例如增加或者刪除空閒區間、統計Rset大小、當前最大可用年輕代、當前最小可用年輕代、設定停頓目標等。我們可以認為這個過程在回收停頓結束後是一個重新調整年輕代的過程。可以通過-XX:+PrintGCDetails選項的執行來檢視具體資料。

併發標記

G1 GC設定了一個閾值,預設值是堆記憶體的45%。這個閾值可以通過選項IHOP設定,IHOP即-XX:InitiatingHeapOccupanyPercent。當超過閾值時,GC會自動進入並行標記迴圈。並行標記迴圈的最終目標是在整個Java堆達到滿載之前完成標記動作,同時為了確保Java應用執行緒可以並行執行,並行標記迴圈的內部標記任務被劃分成了很多塊任務,這樣可以做到並行執行。

並行標記迴圈的過程分為五個階段:

1.初始標記階段

把java堆中所有能被根可達的物件標記出來,在此期間應用執行緒暫停。

2.根區間掃描階段

併發掃描和跟蹤survivor區所有物件引用。

3.並行標記階段

多個執行緒協同表示存活物件。併發並行執行。

4.重新標記階段

最終完成所有標記工作,短暫stop-the-world。

5.清除階段

將沒有任何存活物件的分割槽回收,梳理RSet,將沒有引用的分割槽加入可用佇列。

混合回收

混合回收和年輕代回收暫停的工作方式類似,也是通過拷貝方式完成針對存活物件的壓縮操作。唯一的區別是在混合回收階段,回收集合也會和一些被認定為是可以做垃圾回收的老年代一起合作,即同時對年輕代和老年代區間進行回收。通過配置一些引數,可以為一次混合回收迴圈設定多次混合回收暫停。一次混合回收迴圈只有在標記或者超過IHOP闊值時才會觸發啟動,且必須發生在一次並行標記迴圈之後。

可配置引數:

-XX:-G1MixedGCCountTarget

DK8u45預設值為8, 意味著混合GC數目目標為8個,即標記迴圈完成之後開始的混合回收數目從物理上被限制在了8個。每一次混合回收暫停的最小老年代區間數目的計算公式為:

每一次混合回收暫停的最小老年代區間數目=混合收集迴圈確認的候選老年代區間總數/G1MixedGCCountTarget。

-XX:G1HeapWastePercent

JDK8U45預設值為整個堆空間的5%, 這個選項對於控制一次混合回收迴圈回收的老年代區間數量有很大的影響作用。對於每一次混合回收暫停, G1 GC基於死亡物件空間確認所有可以回收的堆記憶體,即事先已經統計好了每個區間還有多少存活物件,通過拷貝的方式移出區間,再把這些區間加入空閒區間。當G1 GC達到堆記憶體空閒閾值百分比限制時,G1 GC停止初始化混合回收暫停。