JVM的幾種垃圾收集器
Serial收集器
基本原理:
- 新生代收集器,採用標記複製算法
- 它是一個單線程收集器,只會使用一個CPU和一條收集線程完成GC。
缺陷:
- 在於它“Stop-The-World”的收集方式。進行垃圾收集時必須暫停其他線程的所有工作
優點:
- 簡單而高效(與其他收集器的單線程比),對於限定單個CPU的環境來說,Serial收集器由於沒有線程交互的開銷,專心做GC反而效率更高。
適用場景:
- 在用戶的桌面應用場景中,分配給虛擬機管理的內存一般來說不會很大,GC停頓時間可接受。因此Serial收集器對於運行在Client模式下的虛擬機來說是一個很好的選擇。
ParNew 收集器
基本原理:
- 新生代收集器,採用標記複製算法
- ParNew收集器其實就是Serial收集器的多線程版本,它使用了多條線程進行GC。其餘行爲包括Serial收集器可用的所有控制參數、收集算法、Stop The World、對象分配規則、回收策略等都與Serial收集器完全一樣。且兩者共用了相當多的代碼。
優點:
- 隨着CPU數量增加,它對於GC時系統資源的有效利用還是很有好處的。
適用場景:
- Server模式下首選的新生代收集器,其中一個重要原因是目前除Serial收集器外,只有它能與CMS收集器相配合。
Parallel Scavenge收集器
基本原理:
- 新生代收集器,採用複製算法
- 採用多線程收集
- 此收集器的重點在於達到一個可控的吞吐量
- 亦稱爲:吞吐量優先收集器
- 所謂吞吐量就是CPU用於運行用戶代碼的時間與CPU總消耗時間的比值,即吞吐量 = 運行用戶代碼時間 / (運行用戶代碼時間 + 垃圾收集時間)。比如,JVM總運行時長100分鐘,GC佔1分鐘,那麼吞吐量就是99%。
優點:
- 具有自適應調節策略
- JVM具有一個參數可以打開此策略。打開後,JVM會根據當前系統的運行情況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間或者最大吞吐量。
使用場景:
- 需要高吞吐量的場景:主要適用在後臺運算而不需要太多交互的任務。
Serial Old收集器
基本原理:
- Serial Old 是 Serial收集器的老年代版本
- 單線程
- 使用“標記整理”算法
適用場景:
- 主要意義在於給Client模式下的JVM使用。
- 在Server下也有量大用途:
- 在JDK 1.5 之前的版本中與 Paroled Scavenge 收集器搭配使用
- 作爲CMS收集器的後備預案,在併發收集失敗下使用
Parallel Old 收集器
基本原理:
- Parallel Scavenge收集器的老年代版本
- 多線程處理
- 使用“標記整理”算法
適用場景:
- 對於注重吞吐量以及CPU資源敏感的場合,都可以優先考慮Parallel Scavenge + Parallel Old收集器
CMS 收集器
基本原理:
- CMS = Concurrent Mark Sweep 併發標記清除
- 目標:獲取最短GC停頓時間
- 青年老年代均有涉獵
- CMS中利用ParNew處理young代
- old代使用標記清除算法,並分步驟進行
運作過程:
- 初始標記
- CMS initial mark
- 需要 Stop-The-World
- 只是標記一下GC roots能直接關聯到的對象,速度很快
- 併發標記
- CMS concurrent mark
- 進行GC RootsTracing的過程,也就是依照初始標記中發現的可達對象尋找其他的可達對象
重新標記
- CMS remark
- 需要 Stop-The-World
- 修正併發標記期間因用戶程序繼續運作而導致標記產生變動的那一部分對象的標記記錄
- 此階段的停頓一般會比初始標記階段稍長一些,但遠比並發標記的時間短
併發清除
- CMS concurrent sweep
- 清理垃圾對象,這個階段收集器線程和應用程序線程併發執行
- 初始標記
優點:
- 整個過程中耗時最長的併發標記和併發清除都可以與用戶線程一起工作。總體上,CMS收集器的內存回收過程是與用戶線程一起併發執行的。
缺點:
- 對CPU資源非常敏感:由於它佔用了一部分線程而導致應用程序變慢 ,總吞吐量會降低。
- 當CPU在4個以上時,併發GC線程佔用不少於25%CPU的資源,並隨着CPU數量的增加而下降。
- 當CPU不足4個,如2個時,CMS對用戶程序的影響就可能變的很大 。如果本來CPU負載就比較大,還分出一半去執行GC線程,就可能導致用戶線程突然變慢。
- 無法處理浮動垃圾(Floating Garbage)
- 浮動垃圾:由於CMS併發清理階段用戶線程還在運行着,伴隨程序運行自然就還會有新的垃圾不斷產生,這部分垃圾出現在標記過程之後,CMS無法在當次收集中處理掉它們,只好等待下一次GC時再清理掉。這部分垃圾就稱爲“浮動垃圾”。
- 可能出現“Concurrent Mode Failure”失敗
- CMS收集器不能像其他收集器那樣等到老年代幾乎完全填滿再進行收集,而是需要預留一部分空間提供併發收集時程序的運作。如果預留空間不夠,就會發生此失敗。失敗後會採用Serial Old進行老年代的收集,這樣停頓時間會增長。
- 如果老年代增長不是太快,可以適當調高觸發值(即老年代佔用多少時會觸發CMS),以降低迴收次數從而獲取更好的性能。
- CMS收集器不能像其他收集器那樣等到老年代幾乎完全填滿再進行收集,而是需要預留一部分空間提供併發收集時程序的運作。如果預留空間不夠,就會發生此失敗。失敗後會採用Serial Old進行老年代的收集,這樣停頓時間會增長。
- 易產生碎片,進而導致FULL GC的方法
- Full GC : 也稱爲“Major GC”專指老年代垃圾回收行爲
- 由於CMS採用 “標記-清除”算法,因此很容易造成碎片問題,進而無法找到足夠空間分配對象,從而觸發Full GC 。
- 解決:提供一默認開啓的JVM參數,讓JVM在CMS頂不住要進行Full GC時開啓內存碎片合併整理過程。
- 此過程無法併發處理,停頓時間不得不變長
適用場景:
- 對於追求服務響應速度,希望GC停頓短的場合十分適用。如網站服務端
G1 收集器
基本原理:
- G1 = Garbage-First
- 面向服務端應用的垃圾收集器
- 雖然保留了新老年代的概念,但是兩者不再是物理隔離了,它們都是一部分Region(不需要連續)的集合
優點:
- 並行與併發:充分利用多核來縮短Stop-The-World時間。G1收集器仍然可以通過併發的方式讓Java程序繼續執行
- 分代回收
- 空間整合:不會產生空間碎片,收集後能提供規整的可用內存,利於程序長時間執行
- 可預測的停頓:讓使用者明確指定在一個長度爲M毫秒的時間片段內,消耗在GC上的時間不得超過N毫秒
- 原因:G1可以有計劃地避免在整個Java堆中進行全區域的垃圾回收
運作過程(與CMS有一定的相似之處):
- 初始標記(Initial Marking)
- 併發標記(Concurrent Marking)
- 最終標記(Final Marking)
- 篩選回收(Live Data Counting and Evacuation)