JVM中的G1垃圾回收器

jopen 9年前發布 | 14K 次閱讀 JVM Java開發

原文  http://www.importnew.com/15311.html


我們先回顧一下主流Java的垃圾回收器(HotSpot JVM)。本文是針對堆的垃圾回收展開討論的。

堆被分解為較小的三個部分。具體分為:新生代、老年代、持久代。

JVM中的G1垃圾回收器

  1. 絕大部分新生成的對象都放在Eden區,當Eden區將滿,JVM會因申請不到內存,而觸發Young GC ,進行Eden區+有對象的Survivor區(設為S0區)垃圾回收,把存活的對象用復制算法拷貝到一個空的Survivor(S1)中,此時Eden 區被清空,另外一個Survivor S0也為空。下次觸發Young GC回收Eden+S0,將存活對象拷貝到S1中。新生代垃圾回收簡單、粗暴、高效。
  2. 若發現Survivor區滿了,則將這些對象拷貝到old區或者Survivor沒滿但某些對象足夠Old,也拷貝到Old區(每次 Young GC都會使Survivor區存活對象值+1,直到閾值)。 3.Old區也會進行垃圾收集(Young GC),發生一次 Major GC 至少伴隨一次Young GC,一般比Young GC慢十倍以上。
  3. JVM在Old區申請不到內存,會進行Full GC。Old區使用一般采用Concurrent-Mark–Sweep策略回收內存。

總結:Java垃圾回收器是一種“自適應的、分代的、停止—復制、標記-清掃”式的垃圾回收器。

缺點:

  1. GC過程中會出現STW(Stop-The-World),若Old區對象太多,STW耗費大量時間。
  2. CMS收集器對CPU資源很敏感。
  3. CMS收集器無法處理浮動垃圾,可能出現“Concurrent Mode Failure”失敗而導致另一次Full GC的產生。
  4. CMS導致內存碎片問題。

G1收集器

在G1中,堆被劃分成 許多個連續的區域(region)。每個區域大小相等,在1M~32M之間。JVM最多支持2000個區域,可推算G1能支持的最大內存為 2000*32M=62.5G。區域(region)的大小在JVM初始化的時候決定,也可以用-XX:G1HeapReginSize設置。

在G1中沒有物理上的Yong(Eden/Survivor)/Old Generation,它們是邏輯的,使用一些非連續的區域(Region)組成的。

新生代收集

G1的新生代收集跟ParNew類似,當新生代占用達到一定比例的時候,開始出發收集。

JVM中的G1垃圾回收器

JVM中的G1垃圾回收器

被圈起的綠色部分為新生代的區域(region),經過Young GC后存活的對象被復制到一個或者多個區域空閑中,這些被填充的區域將是新的新生代;當新生代對象的年齡(逃逸過一次Young GC年齡增加1)已經達到某個閾值(ParNew默認15),被復制到老年代的區域中。

回收過程是停頓的(STW,Stop-The-Word);回收完成之后根據Young GC的統計信息調整Eden和Survivor的大小,有助于合理利用內存,提高回收效率。

回收的過程多個回收線程并發收集。

老年代收集

和CMS類似,G1收集器收集老年代對象會有短暫停頓。

  1. 標記階段,首先初始標記(Initial-Mark),這個階段是停頓的(Stop the World Event),并且會觸發一次普通Mintor GC。對應GC log:GC pause (young) (inital-mark)
  2. Root Region Scanning,程序運行過程中會回收survivor區(存活到老年代),這一過程必須在young GC之前完成。
  3. Concurrent Marking,在整個堆中進行并發標記(和應用程序并發執行),此過程可能被young GC中斷。在并發標記階段,若發現區域對象中的所有對象都是垃圾,那個這個區域會被立即回收(圖中打X)。同時,并發標記過程中,會計算每個區域的對象活 性(區域中存活對象的比例)。 JVM中的G1垃圾回收器
  4. Remark, 再標記,會有短暫停頓(STW)。再標記階段是用來收集 并發標記階段 產生新的垃圾(并發階段和應用程序一同運行);G1中采用了比CMS更快的初始快照算法:snapshot-at-the-beginning (SATB)。
  5. Copy/Clean up,多線程清除失活對象,會有STW。G1將回收區域的存活對象拷貝到新區域,清除Remember Sets,并發清空回收區域并把它返回到空閑區域鏈表中。 JVM中的G1垃圾回收器
  6. 復制/清除過程后。回收區域的活性對象已經被集中回收到深藍色和深綠色區域。

JVM中的G1垃圾回收器

關于Remembered Set概念:G1收集器中,Region之間的對象引用以及其他收集器中的新生代和老年代之間的對象引用是使用Remembered Set來避免掃描全堆。G1中每個Region都有一個與之對應的Remembered Set,虛擬機發現程序對Reference類型數據進行寫操作時,會產生一個Write Barrier暫時中斷寫操作,檢查Reference引用的對象是否處于不同的Region之間(在分代中例子中就是檢查是否老年代中的對象引用了新生 代的對象),如果是便通過CardTable把相關引用信息記錄到被引用對象所屬的Region的Remembered Set中。當內存回收時,在GC根節點的枚舉范圍加入Remembered Set即可保證不對全局堆掃描也不會有遺漏。

G1雖然保留了CMS關于代的概念,但是代已經不是物理上連續區域,而是一個邏輯的概念。在標記過程中,每個區域的對象活性都被計算,在回收時 候,就可以根據用戶設置的停頓時間,選擇活性較低的區域收集,這樣既能保證垃圾回收,又能保證停頓時間,而且也不會降低太多的吞吐量。Remark階段新 算法的運用,以及收集過程中的壓縮,都彌補了CMS不足。引用Oracle官網的一句話:“G1 is planned as the long term replacement for the Concurrent Mark-Sweep Collector (CMS)”。

參考:

  1. Memory Management in the Java HotSpot? Virtual Machine
  2. Getting Started with the G1 Garbage Collector
  3. 垃圾優先型垃圾回收器調優
  4. 深入理解Java虛擬機:JVM高級特性與最佳實踐

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!