JVM面試必問:G1垃圾回收器


摘要:G1垃圾回收器是一款主要面向服務端應用的垃圾收集器。

本文分享自華為雲社區《JVM面試高頻考點:由淺入深帶你了解G1垃圾回收器!!!》,原文作者:Code皮皮蝦 。

G1垃圾回收器介紹

G1垃圾回收器是一款主要面向服務端應用的垃圾收集器。作為垃圾回收器技術發展史上里程碑的成果,G1垃圾回收器不同於以往的垃圾回收器,首先是思想上的轉變,如下圖:

G1對於Java堆的划分

上面的圖,小伙伴們第一次看可能不咋明白,因為各位還不了解G1,看看下面的話,應該就差不多了。

G1垃圾回收器對於Java堆區域的划分不同於以往我們對Java對區域划分的認知

以往對於Java堆區域的划分為:新生代和老年代,新生代又划分為 Eden區和 Survivor區,Survivor區又分為 from區和 to區。

但是現在,G1不再堅持固定大小以及固定數量的分代區域划分,而是把連續的Java堆空間划分為多個大小相等的獨立區域(Region),每個Region都可以成為 Eden空間、Survivor空間、老年代空間。

這種思想上的轉變和設計,使得G1可以面向堆內存任何部分來組成回收集來進行回收,衡量標准不再是它屬於哪個分代,而是哪塊內存存放的垃圾最多,回收收益最大,這就是G1收集器的 Mixed GC模式,即混合GC模式。

Region還有一類特殊的 Humongous 區域,專門用來存儲大對象。G1認為只要大小超過了一個Region容量一半的對象即可判定為大對象。如果是那些超過了整個Region容量的超大對象,將會放在連續 N 個 Humongous Region區域。

Region的取值范圍為 1M ~ 32M

Region的默認個數為 2048個

-XX:G1HeapRegionSize = N

G1這么做看起來是由一種煥然一新的感覺,但細心的小伙伴可能已經發現,如果 Region之間存在跨區引用對象,那這些對象如何解決?

  1. 不管是G1還是其他分代收集器,JVM都是使用 記憶集(Remembered Set) 來避免全局掃描。
  2. 每個Region都有一個對應的記憶集。
  3. 每次Reference類型數據寫操作時,都會產生一個 寫屏障(Write Barrier)暫時去終止操作
  4. 然后檢查將要寫入的引用 指向的對象是否和該Reference類型數據在不同的 Region(其他收集器:檢查老年代對象是否引用了新生代對象)
  5. 如果不同,通過 卡表(Card Table)把相關引用信息記錄到引用指向對象的所在Region對應的記憶集(Remembered Set) 中
  6. 當進行垃圾收集時,在GC Roots枚舉范圍加上記憶集;就可以保證不進行全局掃描了。

G1的記憶集可以理解為一個哈希表,Key就是別的Region的起始地址,Value就是卡表的索引號集合。

因為G1將Java堆划分為一個個Region的緣故,而Region數量相比於傳統分代數量明顯多得多,所以G1相比於傳統的垃圾回收器來說,需要消耗相當於Java堆容量 10%~ 20%的額外空間來維持收集器的工作。

G1 垃圾回收器工作流程

  • 初始標記(Initial Marking):這階段僅僅只是標記GC Roots能直接關聯到的對象並修改TAMS(Next Top at Mark Start)的值,讓下一階段用戶程序並發運行時,能在正確的可用的Region中創建新對象,這階段需要停頓線程,但是耗時很短。而且是借用進行Minor GC的時候同步完成的,所以G1收集器在這個階段實際並沒有額外的停頓。
  • 並發標記(Concurrent Marking):從GC Roots開始對堆的對象進行可達性分析,遞歸掃描整個堆里的對象圖,找出存活的對象,這階段耗時較長,但是可以與用戶程序並發執行。當對象圖掃描完成以后,還要重新處理SATB記錄下的在並發時有引用變動的對象。
  • 最終標記(Final Marking):對用戶線程做另一個短暫的暫停,用於處理並發階段結束后仍遺留下來的最后那少量的 SATB 記錄。
  • 篩選回收(Live Data Counting and Evacuation):負責更新 Region 的統計數據,對各個 Region 的回收價值和成本進行排序,根據用戶所期望的停頓時間來制定回收計划。可以自由選擇多個Region來構成會收集,然后把回收的那一部分Region中的存活對象==復制==到空的Region中,在對那些Region進行清空。

除了並發標記外,其余過程都要 STW

G1和CMS的區別

  • G1從整體上來看是 標記-整理 算法,但從局部(兩個Region之間)是復制算法。而CMS是 標記-清除算法 所以說,G1不會產生內存碎片,而CMS會產生內存碎片
  • CMS使用了 寫后屏障來維護卡表,而G1不僅使用了寫后屏障來維護卡表,還是用了 寫前屏障來跟蹤並發時的指針變化情況(為了實現原始快照)。
  • CMS對Java堆內存使用的是傳統的 新生代和老年代划分方法,而G1使用的全新的划分方法。
  • CMS收集器只收集老年代,可以配合新生代的Serial和ParNew收集器一起使用。G1收集器收集范圍是老年代和新生代。不需要結合其他收集器使用
  • CMS使用 增量更新解決並發標記下出現的錯誤標記問題,而G1使用原始快照解決

 

點擊關注,第一時間了解華為雲新鮮技術~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM