☕[JVM技術指南](3)垃圾回收子系統(Garbage Collection System)之垃圾回收器

liboware發表於2021-06-12

如果說收集演算法是記憶體回收的方法論,那麼垃圾收集器就是記憶體回收的實踐者

☕[JVM技術指南](3)垃圾回收子系統(Garbage Collection System)之垃圾回收器的介紹和實現

這7種作用於不同分代的垃圾收集器,如果兩個收集器之間有連線,就說明它們可以搭配使用,收集器所處的位置表示它們是屬於新生代收集器或老年代收集器。

Serial收集器是一個單執行緒工作的收集器,但它的“單執行緒”的意義不僅僅是它只會使用一個處理器或一個收集執行緒去完成垃圾收集工作,更重要的是強調它在進行垃圾回收的時候,必須暫停其他所有工作執行緒,直到它回收結束為止。

“Stop The World”這項工作是由虛擬機器在後臺自動發起完成的,在使用者不可知、不可控的情況下,把使用者正常工作的執行緒全部停掉,這對很多應用來說是不能接受的。

☕[JVM技術指南](3)垃圾回收子系統(Garbage Collection System)之垃圾回收器的介紹和原理(不包含ZGC)

從JDK1.3到現在最新的JDK17,HotSpot虛擬機器開發團隊為消除或者降低使用者執行緒因垃圾收集而導致停頓的努力一直在持續進行著,從Serial收集器到Parallel收集器,到Concurrent Mark Sweep(CMS)和Garbage First(G1)收集器,到現在收集器最前沿成功Shenandoah和ZGC等,使用者執行緒的停頓時間在持續縮短,但仍然沒辦法徹底消除。

Serial依然是Hotspot虛擬機器執行在客戶端模式下的預設新生代收集器,它優於其他收集器的地方是簡單而高效(與其他收集器的單執行緒相比),是所有收集器額外記憶體消耗最小的,由於沒有執行緒互動的開銷,專心做垃圾收集自然可以獲得最高的單執行緒收集效率。

ParNew收集器是Serial收集器的多執行緒並行版本,除了使用多條執行緒進行垃圾收集之外,其餘的行為包括Serial收集器可用的所有控制引數。

例如:-XX:SurvivorRatio、-XX:PretenureSizeThreshold、-XX:HandlePromotionFailure等)、收集演算法、Stop The World、物件分配規則、回收策略等都與Serial收集器完全一致。

☕[JVM技術指南](3)垃圾回收子系統(Garbage Collection System)之垃圾回收器的介紹和原理(不包含ZGC)

ParNew是執行在伺服器端模式下的HotSpot虛擬機器,很重要的原因是:除了Serial收集器之外,目前只有它能與CMS收集器配合工作,ParNew預設開啟的收集執行緒數與處理器核心數量相同,可以通過-XX:ParallelGCThreads引數來限制垃圾收集的執行緒數。

CMS收集器是HotSpot虛擬機器中第一款真正意義上支援併發的垃圾收集器,它首次實現了讓垃圾收集執行緒與使用者執行緒同時工作。ParNew收集器是啟用CMS後的預設新生代收集器,使用-XX:+UseConcMarkSweepGC選項。

Parallel Scavenge表面上看與ParNew非常相似,同樣是一款新生代收集器,基於標記——複製演算法實現的收集器,能夠並行收集的多執行緒收集器。但是,Parallel Scavenge收集器的目標則是達到一個可控制的吞吐量。

吞吐量 = 執行使用者程式碼時間 / (執行使用者程式碼時間 + 執行垃圾程式碼時間)

Serial Old是Serial收集器的老年代版本,它同樣是一個單執行緒收集器,使用標記——整理演算法。

☕[JVM技術指南](3)垃圾回收子系統(Garbage Collection System)之垃圾回收器的介紹和原理(不包含ZGC)

Parallel Old是Parallel Scavenge收集器的老年代版本,支援多執行緒併發收集,基於標記——整理演算法實現。

直到Parallel Old出現後,“吞吐量優先”收集器終於有了名副其實的搭配組合,在注重吞吐量或者處理器資源較為稀缺的場合,都可以優先考慮Parallel Scavenge加Parallel Old收集器這個組合。

☕[JVM技術指南](3)垃圾回收子系統(Garbage Collection System)之垃圾回收器的介紹和原理(不包含ZGC)

CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器。目前很多Java應用集中在網際網路網站或基於瀏覽器的B/S系統的服務端上,這類應用通常都較為關注服務的響應速度,希望系統停頓時間儘可能短,給使用者帶來良好的互動體驗。

☕[JVM技術指南](3)垃圾回收子系統(Garbage Collection System)之垃圾回收器的介紹和原理(不包含ZGC)

CMS收集器整個過程分為四個步驟:

  1. 初始標記(STW)
  2. 併發標記
  3. 重新標記(STW)
  4. 併發清除

在初始標記、重新標記這兩個步驟仍然需要“Stop The World”。

  • 初始標記僅僅標記一下GC Roots能直接關聯到的物件,速度很快;

  • 併發標記是從GC Roots的直接關聯物件開始遍歷整個物件圖的過程,這個過程畢竟耗時但是不需要停頓使用者執行緒,可以與垃圾收集執行緒一起併發執行;

  • 重新標記是為了修正併發標記期間,因使用者程式繼續執行而導致標記產生變化的那部分物件的標記記錄(增量更新),這個階段耗時比初始階段稍長,比並發階段稍短;

  • 併發清除階段,清理刪除掉標記階段判斷的已經死亡的物件,這個階段也是可以和使用者執行緒同時併發的。

Garbage First(G1)收集器是垃圾收集器技術發展歷史上的里程碑的成果,它開創了收集器面向區域性收集的設計思路和基於Region的記憶體佈局形式。

G1不在堅持固定大小以及固定數量的分代區域劃分,而是把連續的Java堆劃分為多個大小相等的對立區域(Region),每個區域都可以根據需要,扮演新生代的Eden空間、Survivor空間或者老年代空間。

收集器能夠堆扮演不同角色的Region採用不同的策略去處理。

☕[JVM技術指南](3)垃圾回收子系統(Garbage Collection System)之垃圾回收器的介紹和原理(不包含ZGC)

G1收集器執行的四個步驟:

  1. 初始標記:只是標記一下GC Roots能直接關聯到的物件,並且修改TAMS指標的值,讓下一階段使用者執行緒併發執行時,能正確的在可用的Region中分配新物件。這個階段需要停頓執行緒,但耗時短。

  2. 併發標記:從GC Roots開始對堆物件進行可達性分析,遞迴掃描整個堆的物件圖,找出要回收的物件,這階段耗時較長,可與使用者程式併發執行。當物件圖掃描完,還要重新處理SATB記錄下的在併發時有引用變動的物件。

  3. 最終標記:對使用者執行緒做另一個短暫的暫停,用於處理併發階段結束後仍遺留下來的最後那少量的SATB記錄。

  4. 篩選回收:負責更新Region的統計資料,對各個Region的回收價值和成本進行排序,根據使用者所期望的停頓時間來制定回收計劃,可以自由選擇任意多個Region構成回收集,然後把那一部分Region的存活物件複製到空的Region中,再清理掉整個舊的Region的全部空間。

☕[JVM技術指南](3)垃圾回收子系統(Garbage Collection System)之垃圾回收器的介紹和原理(不包含ZGC)

  1. -XX:+UseSerialGC = Serial + Serial Old

預設情況下不會是這種選項,HotSpot虛擬機器會根據計算及配置和JDK版本自動選擇收集器

  1. -XX:+UseParNewGC = ParNew + SerialOld

這個組合已經很少用(在某些版本中已經廢棄)

  1. -XX:+UseConcMarkSweepGC = ParNew + CMS + Serial Old

  2. -XX:+UseParallelGC = Parallel Scavenge + Parallel Old (1.8預設)

  3. -XX:+UseParallelOldGC = Parallel Scavenge + Parallel Old

UseParallelGC 與 UseParallelOldGC 的區別:

-XX:+UseParallelGC = Parallel Scavenge + Parallel Old
-XX:+UseParallelOldGC = Parallel Scavenge + Parallel Old
-XX:-UseParallelOldGC = Parallel Scavenge + Serial Old
  1. -XX:+UseG1GC = G1

  2. 檢視JDK8預設使用的垃圾收集器

1.8預設的垃圾收集器是:Parallel Scavenge + Parallel Old

java +XX:+PrintCommandLineFlags -version
java -XX:+PrintGCDetails -version

☕[JVM技術指南](4)垃圾回收子系統(Garbage Collection System)之G1垃圾收集器SATB

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章