GC相關知識簡單學習

CodersCoder發表於2020-11-29

識別垃圾方法

引用計數法(Reference Counting): 對每個物件的引用進行計數,每當有一個地方引用它時計數器 +1、引用失效則 -1,引用的計數放到物件頭中,大於 0 的物件被認為是存活物件。雖然迴圈引用的問題可通過 Recycler 演算法解決,但是在多執行緒環境下,引用計數變更也要進行昂貴的同步操作,效能較低,早期的程式語言會採用此演算法。
可達性分析,又稱引用鏈法(Tracing GC): 從 GC Root 開始進行物件搜尋,可以被搜尋到的物件即為可達物件,此時還不足以判斷物件是否存活/死亡,需要經過多次標記才能更加準確地確定,整個連通圖之外的物件便可以作為垃圾被回收掉。目前 Java 中主流的虛擬機器均採用此演算法。

收集演算法

Mark-Sweep(標記-清除): 回收過程主要分為兩個階段,第一階段為追蹤(Tracing)階段,即從 GC Root 開始遍歷物件圖,並標記(Mark)所遇到的每個物件,第二階段為清除(Sweep)階段,即回收器檢查堆中每一個物件,並將所有未被標記的物件進行回收,整個過程不會發生物件移動。整個演算法在不同的實現中會使用三色抽象(Tricolour Abstraction)、點陣圖標記(BitMap)等技術來提高演算法的效率,存活物件較多時較高效。
Mark-Compact (標記-整理): 這個演算法的主要目的就是解決在非移動式回收器中都會存在的碎片化問題,也分為兩個階段,第一階段與 Mark-Sweep 類似,第二階段則會對存活物件按照整理順序(Compaction Order)進行整理。主要實現有雙指標(Two-Finger)回收演算法、滑動回收(Lisp2)演算法和引線整理(Threaded Compaction)演算法等。
Copying(複製): 將空間分為兩個大小相同的 From 和 To 兩個半區,同一時間只會使用其中一個,每次進行回收時將一個半區的存活物件通過複製的方式轉移到另一個半區。有遞迴(Robert R. Fenichel 和 Jerome C. Yochelson提出)和迭代(Cheney 提出)演算法,以及解決了前兩者遞迴棧、快取行等問題的近似優先搜尋演算法。複製演算法可以通過碰撞指標的方式進行快速地分配記憶體,但是也存在著空間利用率不高的缺點,另外就是存活物件比較大時複製的成本比較高。

收集器

1 分代收集器
ParNew: 一款多執行緒的收集器,採用複製演算法,主要工作在 Young 區,可以通過 -XX:ParallelGCThreads 引數來控制收集的執行緒數,整個過程都是 STW 的,常與 CMS 組合使用。
CMS: 以獲取最短回收停頓時間為目標,採用“標記-清除”演算法,分 4 大步進行垃圾收集,其中初始標記和重新標記會 STW ,多數應用於網際網路站或者 B/S 系統的伺服器端上,JDK9 被標記棄用,JDK14 被刪除。
2 分割槽收集器
G1: 一種伺服器端的垃圾收集器,應用在多處理器和大容量記憶體環境中,在實現高吞吐量的同時,儘可能地滿足垃圾收集暫停時間的要求。
ZGC: JDK11 中推出的一款低延遲垃圾回收器,適用於大記憶體低延遲服務的記憶體管理和回收,SPECjbb 2015 基準測試,在 128G 的大堆下,最大停頓時間才 1.68 ms,停頓時間遠勝於 G1 和 CMS。
Shenandoah: 由 Red Hat 的一個團隊負責開發,與 G1 類似,基於 Region 設計的垃圾收集器,但不需要 Remember Set 或者 Card Table 來記錄跨 Region 引用,停頓時間和堆的大小沒有任何關係。停頓時間與 ZGC 接近。
3 其他收集器
Metronome、Stopless、Staccato、Chicken、Clover 等實時回收器,Sapphire、Compressor、Pauseless 等併發複製/整理回收器,Doligez-Leroy-Conthier 等標記整理回收器。

相關文章