Java中垃圾收集器都有哪些?又是如何配合進行垃圾回收的?它們的使用場景是什麼? — JVM系列(九)

前言

垃圾回收算法,我們已經瞭解過。

那麼有哪些垃圾收集器?它們的使用場景是什麼?

它們又是如何運用垃圾回收算法來進行垃圾回收的呢?

一、Serial收集器

新生代的收集器。採取的複製算法。

單線程的收集器,它只會使用一個CPU或一條收集線程去完成垃圾收集工作。

在它進行垃圾收集時,必須暫停其他所有的用戶線程,直到它收集結束。

HotSpot虛擬機爲消除或者減少工作線程因內存回收而導致停頓的努力一直在進行着。

Serial收集器是虛擬機運行在Client模式下的默認新生代收集器。也是比較好的選擇。

二、ParNew收集器

ParNew收集器其實就是Serial收集器的多線程版本。也就是虛擬機會使用多線程來進行垃圾回收,但仍然是停止所有的用戶線程。

它是許多運行在Server模式下的虛擬機中首選的新生代收集器。

可以與CMS老年代的垃圾收集器配合使用。

ParNew收集器在單CPU的環境中絕對不會有比Serial收集器更好的效果。當然隨着使用的CPU的數量的增加,它對於GC時系統資源的有效使用還是很有好處的。

默認開啓的線程數與CPU數量相同。可以使用參數來指定垃圾收集的線程數目。

三、Parallel Scavenge—吞吐量優先

新生代的收集器,使用複製算法。並行的線程收集器。

關注點與其他收集器不同,其他收集器的關注點是儘可能的縮短垃圾收集時用戶線程的停頓時間。

而Parallel Scavenge收集器的目標則是達到一個可控制的吞吐量。

所謂吞吐量就是CPU用於運行用戶代碼的時間與CPU總消耗時間的比值。

吞吐量 = 運行用戶代碼時間 / (運行用戶代碼時間 + 垃圾收集時間),例如每100分鐘的時間裏,需要1分鐘的時間做垃圾收集,那麼吞吐量就是99%。

停頓時間越短就越適合需要與用戶交互的程序,良好的響應速度能提升用戶體驗。

高吞吐量則可以高效地利用CPU時間,儘快完成程序的運算任務。主要適合在後臺運算而不需要太多交互的任務。

Parallel Scavenge收集器提供了兩個參數用於精確控制吞吐量,它是吞吐量優先的收集器。

四、Serial Old收集器

是Serial 收集器的老年代版本,也是一個單線程的收集器。

使用標記—整理算法。

這個收集器的主要意義也是在於給Client模式下的虛擬機使用。

五、Parallel Old收集器

Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程和標記—整理算法。

在注重吞吐量及CPU資源敏感的場合,都可以優先考慮Parallel Scavenge加Parallel Old收集器。

六、CMS收集器

以獲取最短回收停頓時間爲目標的收集器。給用戶帶來較好的體驗。併發收集,低停頓。

使用標記—清除算法實現的。

整個過程分爲4個步驟:

  1. 初始標記:仍然需要Stop The World。僅僅是標記一下GC Roots能直接關聯到的對象,速度很快。
  2. 併發標記:就是進行GC Roots Tracing的過程。
  3. 重新標記:仍然需要Stop The World。爲了修正併發標記期間因用戶程序繼續運作而導致標記產生變動的那一部分對象的標記記錄,這個階段的停頓時間一般會比初始標記階段稍長一些,但遠比並發標記的時間短。
  4. 併發清除

由於整個過程中耗時最長的併發標記和併發清除過程收集器線程都可以與用戶線程一起工作,所以,從總體上來說,CMS收集器的內存回收過程是與用戶線程一起併發執行的

CMS收集器的缺點:

  1. CMS無法處理浮動垃圾:因爲併發清除階段,還會有新的垃圾產生,但是本次無法清除,稱爲浮動垃圾。
  2. 基於標記—清除算法實現,會有大量空間碎片產生,將會給大對象分配帶來很大麻煩,即使老年代有很多剩餘空間,但是無法找到足夠大的連續空間來分配當前對象。

七、G1收集器

G1是一款面向服務端應用的垃圾收集器,具備以下特點:

  • 在GC收集的時候,用戶線程仍然可以繼續執行。
  • G1中仍然有分代的概念,但是會採用不同的方式去處理新建對象和已經存活了一段時間的對象。
  • 整體上來看是基於標記—整理算法實現的收集器,從局部(兩個Region之間)上來看是基於複製算法實現的。這都意味着G1運作期間不會產生內存空間碎片,收集後能提供規整的可用內存。
  • 可預測的停頓:G1除了追求低停頓外,還能建立可預測的停頓時間模型,能讓使用者明確指定在一個長度爲M毫秒的時間片段內,消耗在收集上的時間不得超過N毫秒

G1將整個Java堆劃分爲多個大小相等的獨立區域Region,雖然還保留新生代與老年代的概念,但新生代和老年代不再是物理隔離的了。它們都是一部分Region(不需要連續)的集合。

G1之所以能建立可預測的停頓時間模型,是因爲它可以有計劃地避免在整個Java堆中進行全區域的垃圾收集,它跟蹤各個Region裏面的垃圾堆積的價值大小(回收所獲得的的空間大小以及回收所需時間的經驗值),在後臺維護一個優先列表,每次根據允許的收集時間,優先回收價值最大的Region。

在G1收集器中,Region之間的對象引用,以及其他收集器中的新生代與老年代之間的對象引用,虛擬機都是使用Remembered Set來避免全堆掃描的。G1中的每個Region都有一個與之對應的Remembered Set,記錄對象被哪些地方引用,在GC根節點的枚舉範圍中加入Remembered Set即可保證不對全堆掃描也不會有遺漏。

如果不計算維護Remembered Set的操作,G1收集器的運作大致可劃分爲以下幾個步驟:

  1. 初始標記:Stop The World。
  2. 併發標記:可以與用戶進程併發。
  3. 最終標記:Stop The World。
  4. 篩選回收:Stop The World。首先對各個Region的回收價值和成本進行排序,根據用戶所期望的GC停頓時間來制定回收計劃。

總結

一表勝前言:

新生代/老年代 Serial Old—老年代 Parallel Old—老年代 CMS—老年代 G1
Serial—新生代 Y N Y N
ParNew—新生代 Y N Y N
Parallel Seavenge—新生代 Y Y N N
G1 N N N Y

以上表格是垃圾收集器的一個搭配總結,可以搭配使用的是Y,不可以搭配使用的是N。

從表格中可以看到:

  • G1是特殊的垃圾收集器,新生代與老年代都使用。
  • 老年代的收集器Serial Old,除了G1無法搭配,其他的新生代都可以與之配合使用。
  • 老年代的收集器Parallel Old,只能與Parallel Seavenge的新生代收集器配合使用。
  • 老年代收集器CMS既可以與新生代Serial,也可以與ParNew配合使用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章