在前面,我們已經了解了JVM的分代收集,知道JVM垃圾收集在新生代主要采用標記-復制演算法,在老年代主要采用標記-清除和標記-整理演算法,接下來,我們看一看JDK默認虛擬機HotSpot的一些垃圾收集器的實作,
1、常見垃圾回收器
首先來看一下JDK 11之前全部可用的垃圾收集器,

圖中列出了七種垃圾收集器,連線表示可以配合使用,所在區域表示它是屬于新生代收集器或是老年代收集器,
這里還標出了垃圾收集器采用的收集演算法,G1收集器比較特殊,整體采用標記-整理演算法,區域采用標記-復制演算法,后面再細講,
1.1、Serial收集器
Serial收集器是最基礎、歷史最悠久的收集器,
如同它的名字(串行),它是一個單執行緒作業的收集器,使用一個處理器或一條收集執行緒去完成垃圾收集作業,并且進行垃圾收集時,必須暫停其他所有作業執行緒,直到垃圾收集結束——這就是所謂的“Stop The World”,
Serial/Serial Old收集器的運行程序如圖:

1.2、ParNew收集器
ParNew收集器實質上是Serial收集器的多執行緒并行版本,使用多條執行緒進行垃圾收集,
ParNew收集器的作業程序如圖所示:

這里值得一提的是Par是Parallel(并行)的縮寫,但需要注意的是,這個并行(Parallel)僅僅是描述同一時間多條GC執行緒協同作業,而不是GC執行緒和用戶執行緒同時運行,ParNew垃圾收集也是需要Stop The World的,
1.3、Parallel Scavenge收集器
Parallel Scavenge收集器是一款新生代收集器,基于標記-復制演算法實作,也能夠并行收集,和ParNew有些類似,但Parallel Scavenge主要關注的是垃圾收集的吞吐量,
所謂吞吐量指的是運行用戶代碼的時間與處理器總消耗時間的比值,這個比例越高,證明垃圾收集占整個程式運行的比例越小,

Parallel Scavenge收集器提供了兩個引數用于精確控制吞吐量:
-
-XX:MaxGCPauseMillis,最大垃圾回收停頓時間,這個引數的原理是空間換時間,收集器會控制新生代的區域大小,從而盡可能保證回收少于這個最大停頓時間,簡單的說就是回收的區域越小,那么耗費的時間也越小,
所以這個引數并不是設定得越小越好,設太小的話,新生代空間會太小,從而更頻繁的觸發GC, -
-XX:GCTimeRatio,垃圾收集時間與總時間占比,這個是吞吐量的倒數,原理和MaxGCPauseMillis相同,
由于與吞吐量關系密切,Parallel Scavenge收集器也經常被稱作“吞吐量優先收集器”,
1.4、Serial Old收集器
Serial Old是Serial收集器的老年代版本,它同樣是一個單執行緒收集器,使用標記-整理演算法,
Serial Old收集器的作業程序如圖:

1.5、Parallel Old收集器
Parallel Old是Parallel Scavenge收集器的老年代版本,支持多執行緒并發收集,基于標記-整理演算法實作,

1.6、CMS收集器
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器,同樣是老年代的收集齊,采用標記-清除演算法,
CMS收集齊的垃圾收集分為四步:
初始標記(CMS initial mark):單執行緒運行,需要Stop The World,標記GC Roots能直達的物件,并發標記((CMS concurrent mark):無停頓,和用戶執行緒同時運行,從GC Roots直達物件開始遍歷整個物件圖,重新標記(CMS remark):多執行緒運行,需要Stop The World,標記并發標記階段產生物件,并發清除(CMS concurrent sweep):無停頓,和用戶執行緒同時運行,清理掉標記階段標記的死亡的物件,
涉及到了多次標記的程序,這里插入一點
三色抽象的知識,三色抽象用來描述物件在垃圾收集程序中的狀態,通常白色代表物件未被掃描到,灰色表示物件被掃描到但未被處理,黑色表示物件及其后代已被處理,在CMS的標記和清除程序中就用到了這種抽象,詳細的可以查看參考【5】,
Concurrent Mark Sweep收集器運行示意圖如下:

優點:CMS最主要的優點在名字上已經體現出來——并發收集、低停頓,
缺點:CMS同樣有三個明顯的缺點,
-
Mark Sweep演算法會導致記憶體碎片比較多
-
CMS的并發能力比較依賴于CPU資源,并發回收時垃圾收集執行緒可能會搶占用戶執行緒的資源,導致用戶程式性能下降,
-
并發清除階段,用戶執行緒依然在運行,會產生所謂的理“浮動垃圾”(Floating Garbage),本次垃圾收集無法處理浮動垃圾,必須到下一次垃圾收集才能處理,如果浮動垃圾太多,會觸發新的垃圾回收,導致性能降低,
1.7、Garbage First收集器
Garbage First(簡稱G1)收集器是垃圾收集器的一個顛覆性的產物,它開創了區域收集的設計思路和基于Region的記憶體布局形式,
雖然G1也仍是遵循分代收集理論設計的,但其堆記憶體的布局與其他收集器有非常明顯的差異,以前的收集器分代是劃分新生代、老年代、持久代等,

G1把連續的Java堆劃分為多個大小相等的獨立區域(Region),每一個Region都可以根據需要,扮演新生代的Eden空間、Survivor空間,或者老年代空間,收集器能夠對扮演不同角色的Region采用不同的策略去處理,

這樣就避免了收集整個堆,而是按照若干個Region集進行收集,同時維護一個優先級串列,跟蹤各個Region回收的“價值,優先收集價值高的Region,
G1收集器的運行程序大致可劃分為以下四個步驟:
-
初始標記(initial mark),標記了從GC Root開始直接關聯可達的物件,STW(Stop the World)執行,
-
并發標記(concurrent marking),和用戶執行緒并發執行,從GC Root開始對堆中物件進行可達性分析,遞回掃描整個堆里的物件圖,找出要回收的物件、
-
最終標記(Remark),STW,標記再并發標記程序中產生的垃圾,
-
篩選回收(Live Data Counting And Evacuation),制定回收計劃,選擇多個Region 構成回收集,把回收集中Region的存活物件復制到空的Region中,再清理掉整個舊 Region的全部空間,需要STW,

相比CMS,G1的優點有很多,可以指定最大停頓時間、分Region的記憶體布局、按收益動態確定回收集,
只從記憶體的角度來看,與CMS的“標記-清除”演算法不同,G1從整體來看是基于“標記-整理”演算法實作的收集器,但從區域(兩個Region 之間)上看又是基于“標記-復制”演算法實作,無論如何,這兩種演算法都意味著G1運作期間不會產生記憶體空間碎片,垃圾收集完成之后能提供規整的可用記憶體,
2、前沿垃圾回收器
2.1、ZGC收集器
在JDK 11當中,加入了實驗性質的ZGC,它的回收耗時平均不到2毫秒,它是一款低停頓高并發的收集器,
與CMS中的ParNew和G1類似,ZGC也采用標記-復制演算法,不過ZGC對該演算法做了重大改進:ZGC在標記、轉移和重定位階段幾乎都是并發的,這是ZGC實作停頓時間小于10ms目標的最關鍵原因,

ZGC雖然在JDK 11還處于實驗階段,但由于演算法與思想是一個非常大的提升,未來前景相信還是很廣闊的,
3、垃圾收集器選擇
3.1、收集器選擇權衡
垃圾收集器的選擇需要權衡的點還是比較多的——例如運行應用的基礎設施如何?使用JDK的發行商是什么?等等……
這里簡單地列一下上面提到的一些收集器的適用場景:
- Serial :如果應用程式有一個很小的記憶體空間(大約100 MB)亦或它在沒有停頓時間要求的單執行緒處理器上運行,
- Parallel:如果優先考慮應用程式的峰值性能,并且沒有時間要求要求,或者可以接受1秒或更長的停頓時間,
- CMS/G1:如果回應時間比吞吐量優先級高,亦或垃圾收集暫停必須保持在大約1秒以內,
- ZGC:如果回應時間是高優先級的,亦或堆空間比較大,
3.1、設定垃圾收集器
設定垃圾收集器(組合)的引數如下:
| 新生代 | 老年代 | JVM 引數 |
|---|---|---|
| Incremental | Incremental | -Xincgc |
| Serial | Serial | -XX:+UseSerialGC |
| Parallel Scavenge | Serial | -XX:+UseParallelGC -XX:-UseParallelOldGC |
| Parallel New | Serial | N/A |
| Serial | Parallel Old | N/A |
| Parallel Scavenge | Parallel Old | -XX:+UseParallelGC -XX:+UseParallelOldGC |
| Parallel New | Parallel Old | N/A |
| Serial | CMS | -XX:-UseParNewGC -XX:+UseConcMarkSweepGC |
| Parallel Scavenge | CMS | N/A |
| Parallel New | CMS | -XX:+UseParNewGC -XX:+UseConcMarkSweepGC |
| G1 | -XX:+UseG1GC |
參考:
【1】:周志朋編著《深入理解Java虛擬機:JVM高級特性與最佳實踐》
【2】:《垃圾回收演算法手冊 自動記憶體管理的藝術》
【3】:Garbage Collection in Java – What is GC and How it Works in the JVM
【4】:Java Hotspot G1 GC的一些關鍵技術
【5】:GC Algorithms: Implementations
【6】:新一代垃圾回收器ZGC的探索與實踐
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/271402.html
標籤:其他
