面試官:說一下JVM常用垃圾回收器的特點、優劣勢、使用場景和參數設置
今天去看牙醫,他問我年級輕輕牙齒怎麼磨損這麼嚴重?我說,沒有人點贊的這些年,我都是咬著牙過來的。
Java中的垃圾回收器幾乎是面試中的必考點,無論是面試初級,中級還是高級,總免不了要問一問垃圾回收器的一些知識點。不管在實際開發中你使用程度怎麼樣,為了面試不被壓價,還是非常有必要對它做一個較深入的理解。
本篇對JVM中常用的幾種垃圾回收器的主要特點,使用場景及優化建議做一個簡單介紹,希望起到拋磚引玉的效果,對你入門有所幫助。
新生代回收器
- Serial
- ParNew
- parallel
老年代回收器
- Serial Old
- CMS
- Parallel Old
新生代和老年代回收器
- G1
Serial
特點
Serial收集器是最基本、發展歷史最悠久的收集器。JDK1.3.1前是HotSpot新生代收集的唯一選擇。
運行示意圖
有如下特點:
- 針對新生代;
- 採用複製演算法;
- 單執行緒收集;
- 進行垃圾收集時,必須暫停所有工作執行緒,直到完成;
優勢:
簡單高效,由於採用的是單執行緒的方法,因此與其他類型的收集器相比,對單個cpu來說沒有了上下文之間的的切換,效率比較高。
劣勢:
會在用戶不知道的情況下停止所有工作執行緒。
使用場景
- Client 模式(桌面應用)
在用戶的桌面應用場景中,可用記憶體一般不大,可以在較短時間內完成垃圾收集,只要不頻繁發生,這是可以接受的
- 單核伺服器
對於限定單個CPU的環境來說,Serial收集器沒有執行緒切換開銷,可以獲得最高的單執行緒收集效率
參數設置
-XX:+UseSerialGC
:添加該參數來顯式的使用串列垃圾收集器
ParNew
特點
ParNew收集器其實就是Serial收集器的多執行緒版本,除了使用多執行緒進行垃圾收集之外,其餘均和Serial 收集器一致。
運行示意圖
優勢:
多執行緒版本的Serial,可以更加有效的利用系統資源
劣勢:
同Serial,會在用戶不知道的情況下停止所有工作執行緒
使用場景
Server模式下使用,亮點是除Serial外,目前只有它能與CMS收集器配合工作,是一個非常重要的垃圾回收器。
參數設置
-XX:+UseConcMarkSweepGC
:指定使用CMS後,會默認使用ParNew作為新生代收集器;-XX:+UseParNewGC
:強制指定使用ParNew;-XX:ParallelGCThreads
:指定垃圾收集的執行緒數量,ParNew默認開啟的收集執行緒與CPU的數量相同;
parallel
特點
Parallel Scavenge也是一款用於新生代的多執行緒收集器,也是採用複製演算法。與ParNew的不同之處在於Parallel Scavenge收集器的目的是達到一個可控制的吞吐量,而ParNew收集器關注點在於儘可能的縮短垃圾收集時用戶執行緒的停頓時間。
運行示意圖
有如下特點:
- 新生代收集器;
- 採用複製演算法;
- 多執行緒收集;
- 關注點與其他收集器不同:
- CMS等收集器的關注點是儘可能地縮短垃圾收集時用戶執行緒的停頓時間;
- 而Parallel Scavenge收集器的目標則是達一個可控制的吞吐量;
優勢:
追求高吞吐量,高效利用CPU,是吞吐量優先,且能進行精確控制。
劣勢:
應該說是特點,追求高吞吐量必然要犧牲一些其他方面的優勢,不能做到既,又。ParNew收集器關注點在於儘可能的縮短垃圾收集時用戶執行緒的停頓時間,原本10s收集一次, 每次停頓100ms, 設置完參數之後可能變成5s收集一次, 每次停頓70ms. 停頓時間變短, 但收集次數變多。
使用場景
根據相關特性,我們很容易想到它的使用場景,即:當應用程式運行在具有多個CPU上,對暫停時間沒有特別高的要求時,程式主要在後台進行計算,而不需要與用戶進行太多交互等就特別適合ParNew收集器。
- 例如,那些執行批量處理、訂單處理、工資支付、科學計算的應用程式等
參數設置
- -XX:MaxGCPauseMillis:控制最大垃圾收集停頓時間,大於0的毫秒數;
- -XX:GCTimeRatio:設置垃圾收集時間佔總時間的比率,0<n<100的整數;
Serial Old
特點
Serial Old是Serial收集器的老年代版本,同樣是一個單執行緒收集器,使用標記-整理演算法。
有如下特點:
- 針對老年代;
- 採用”標記-整理”演算法(還有壓縮,Mark-Sweep-Compact);
- 單執行緒收集;
優劣勢基本和Serial無異,它是和Serial收集器配合使用的老年代收集器。
使用場景
- Client模式;
- 單核伺服器;
- 與Parallel Scavenge收集器搭配;
- 作為CMS收集器的後備方案,在並發收集發生Concurrent Mode Failure時使用
CMS
特點
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器。採用的演算法是「標記-清除」,運作過程分為四個步驟:
- 初始標記,標記GC Roots 能夠直接關聯到達對象
- 並發標記,進行GC Roots Tracing 的過程
- 重新標記,修正並發標記期間因用戶程式繼續運作而導致標記產生變動的那一部分標記記錄
- 並發清除,用標記清除演算法清除對象。
運行示意圖
有如下特點:
- 針對老年代;
- 基於”標記-清除”演算法(不進行壓縮操作,產生記憶體碎片);
- 以獲取最短回收停頓時間為目標;
- 並發收集、低停頓;
- 需要更多的記憶體(看後面的缺點);
優勢:
- 停頓時間短;
- 吞吐量大;
- 並發收集
劣勢:
- 對CPU資源非常敏感
- 無法收集浮動垃圾
- 容易產生大量記憶體碎片
使用場景
- 與用戶交互較多的場景;
- 希望系統停頓時間最短,注重服務的響應速度;
- 以給用戶帶來較好的體驗;
如常見WEB、B/S系統的伺服器上的應用。
參數設置
-XX:+UseConcMarkSweepGC
:指定使用CMS收集器
Parallel Old
特點
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多執行緒和「標記-整理」演算法,可以充分利用多核CPU的計算能力。
有如下特點:
- 針對老年代;
- 採用”標記-整理”演算法;
- 多執行緒收集;
優劣勢參考Parallel Scavenge收集器。
使用場景
- JDK1.6及之後用來代替老年代的Serial Old收集器;
- 特別是在Server模式,多CPU的情況下;
這樣在注重吞吐量以及CPU資源敏感的場景,就有了Parallel Scavenge(新生代)加Parallel Old(老年代)收集器的”給力”應用組合;
參數設置
-XX:+UseParallelOldGC
:指定使用Parallel Old收集器
G1
特點
G1(Garbage-First)是JDK7-u4才推出商用的收集器
- 並行與並發:G1能充分利用多CPU,多核環境下的硬體優勢。
- 分代收集:能夠採用不同的方式去處理新創建的對象和已經存活了一段時間的對象,不需要與其他收集器進行合作。
- 空間整合:G1從整體上來看基於「標記-整理」演算法實現的收集器,從局部上看是基於複製演算法實現的,因此G1運行期間不會產生空間碎片。
- 可預測的停頓:G1能建立可預測的時間停頓模型,能讓使用者明確指定一個長度為M毫秒的時間片段內,消耗在垃圾收集上的時間不得超過N毫秒。
運行示意圖
有如下特點:
- 並行與並發
- 分代收集,收集範圍包括新生代和老年代
- 結合多種垃圾收集演算法,空間整合,不產生碎片
- 可預測的停頓:低停頓的同時實現高吞吐量
- 面向服務端應用,將來替換CMS
優勢:
- 能充分利用多CPU、多核環境下的硬體優勢;
- 能獨立管理整個GC堆(新生代和老年代),而不需要與其他收集器搭配;
- 不會產生記憶體碎片,有利於長時間運行;
- 除了追求低停頓處,還能建立可預測的停頓時間模型;
G1收集器是當今收集器技術發展的最前沿成果。
劣勢:
G1 需要記憶集 (具體來說是卡表)來記錄新生代和老年代之間的引用關係,這種數據結構在 G1 中需要佔用大量的記憶體,可能達到整個堆記憶體容量的 20% 甚至更多。而且 G1 中維護記憶集的成本較高,帶來了更高的執行負載,影響效率。
按照《深入理解Java虛擬機》作者的說法,CMS 在小記憶體應用上的表現要優於 G1,而大記憶體應用上 G1 更有優勢,大小記憶體的界限是6GB到8GB。
所以,儘管是最前沿的成果,也不是完美無缺的。
使用場景
個人以為G1已經基本全面壓制cms、parallel等回收器,缺點見上面的劣勢。但如果不是追求極致的性能,基本可以無腦G1
參數設置
-XX:+UseG1GC
:指定使用G1收集器;-XX:InitiatingHeapOccupancyPercent
:當整個Java堆的佔用率達到參數值時,開始並發標記階段;默認為45;-XX:MaxGCPauseMillis
:為G1設置暫停時間目標,默認值為200毫秒;-XX:G1HeapRegionSize
:設置每個Region大小,範圍1MB到32MB;目標是在最小Java堆時可以擁有約2048個Region;
基本就介紹這些了,垃圾回收器基本不變的知識點多,學會(理解)可以應付N年的相關知識的面試,又是高頻面試考點,各位同學還是值得在這塊下點功夫的。文中有任何不足,錯誤歡迎指出,共同進步!