天天看點

Java垃圾回收機制-垃圾收集器(二)

上篇總結了常見的垃圾收集算法,這裡回顧下常見的垃圾收集器。

Java垃圾回收機制-垃圾收集器(二)

image.png

上圖展示了7種不同分代的垃圾收集器,如果兩個收集器之間存在連線,說明他們之間可以搭配使用。虛拟機所處的區域,代表它是新生代收集器還是老年代收集器。

下面依次介紹各自收集器,沒有最好的收集器,針對不同的場景選擇适合自己的收集器。

Serial收集器

它是最基本、發展曆史最為悠久的收集器,單線程的收集器,在執行收集時,必須暫停其它的工作線程,直到它收集結束。早些年Java卡頓的現象就是由它導緻的。

Java垃圾回收機制-垃圾收集器(二)

兩大特點:

  • 它僅僅使用單線程進行垃圾回收
  • 它獨占式的垃圾回收

雖然串行收集器進行垃圾回收時給使用者帶來的體驗極差,但是它簡單高效,對于記憶體不是很大的場景一般停頓時間可以控制在很低幾乎感覺不到。隻要不頻繁發生,小小的停頓還是可以接受的。

Serial收集器對于運作在Client模式下的虛拟機來說是一個好的選擇。

參數:

-XX:+UseSerialGC 指定使用新生代串行收集器和老年代串行收集器。

ParNew收集器

它是Serial收集器的多線程版本,除了使用多條線程進行垃圾收集之外,其餘行為包括Serial收集器所有的控制參數,實作上兩者也共用了相當多的代碼。

它是運作在Server模式下的首選新生代收集器。

ParNew收集器在單線程環境中,效果不會比Serial好。在CPU的數量增加下,在GC時可以更好的利用資源。

-XX:+UseParNewGC 表示新生代使用并行收集器,老年代使用串行收集器

-XX:ParallelGCThreads 限制垃圾收集器的線程數

Parallel Scavenge

也是新生代收集器,也使用複制算法,又是并行的。Parallel Scanvenge收集器的特點是它的關注點是達到可控制的吞吐量(Throughout)

總運作時間 = 運作使用者代碼時間 + 垃圾收集時間

吞吐量 = 運作使用者代碼時間 / (運作使用者代碼時間 + 垃圾收集時間)

停頓時間越短越适合需要與使用者互動的程式,良好的響應速度能提升使用者體驗,而高吞吐量可以更高效的利用CPU的時間,盡快完成程式的運算任務,主要适合在背景計算而不需要太多的互動任務。

-XX:+UseParallelGC:新生代使用并行回收收集器,老年代使用串行收集器。

-XX:+UseParallelOldGC:新生代和老年代都是用并行回收收集器

-XX:MaxGCPauseMillis 垃圾收集器最大的停頓時間,機關為毫秒

-XX:GCTimeRatio 直接設定吞吐量大小,垃圾收集時間占總時間的比值。

-XX:UseAdaptiveSizePolicy 打開這個參數之後,就不用手動設定新生代,老年代的比例了,虛拟機會根據目前的運作情況自動調整。自适應政策也是Parallel Scanvenge與ParNew收集器的一個差別。

Serial Old

它是Serial收集器的老年代版本,通用是單線程,使用标記壓縮算法,也是主要給client模式下的虛拟機使用。

如果用在Server模式下,則是與Parallel Scavenge收集器搭配使用。

Parallel Old

Parallel Scavenge收集器的老年代版本,使用多線程的标記-整理算法,比Serial Old收集器出現的晚,可以更充分的利用多CPU的能力。

多CPU的情況下可以使用Parallel Old

CMS收集器

CMS(Concurrent Mark Sweep)收集器是一種以擷取最短回收停頓時間為目标的收集器,注重服務的響應速度,希望系統停頓時間最短,CMS收集器非常适合這類應用的需求。

使用标記清除算法,過程有4個步驟:

  • 初始标記
  • 并發标記
  • 重新标記
  • 并發清除

初始标記和重新标記,兩個步驟仍需要停頓,初始标記僅僅是标記一下GC Roots能直接關聯到的對象,速度很快。并發階段就是GC Root Tracing的過程,重新标記階段則是對使用者程式繼續運作而導緻标記變動的一部分對象标記記錄,這個階段時間也很端比初始标記長,并發标記短。

CMS的缺點:

  • 對CPU資源非常敏感,需保證足夠的CPU資源
  • 标記清除算法的缺點,會有大量的空間碎片
  • 無法處理浮動垃圾,程式不斷的運作就會有不斷的垃圾産生,而CMS收集器無法集中處理它們,隻好在下次GC時清理掉。

根據描述,可以看到CMS收集器适合那些伺服器資源比較多人使用,記憶體充足,CPU充足,然後使用CMS收集器。

G1收集器

G1收集器是當今收集器技術發展的最前沿成果之一。

它的特點:

  • 并行與并發,停頓時間更短
  • 分代收集,仍然有分代概念
  • 空間整合,不會産生碎片
  • 可預測的停頓,可以設定停頓時間在多少範圍内

在G1之前進行收集的範圍都是整個新生代或老年代,而G1不再是這樣,使用G1收集器的時候,Java堆的記憶體布局就與其它的收集器有很大的差別,它将整個Java堆劃分為多個大小相等的獨立區域,雖然還保有區域的概念,但新生代和老年代已經不再是實體隔離的了。

G1收集器過程:

  • 初始标記 标記GCRoots 能直接關聯到的對象
  • 并發标記 進行可達性分析,找出存活對象,耗時稍長
  • 最終标記 标記并發标記期間因使用者程式繼續運作而導緻的标記變動
  • 篩選回收 對各個Region區域回收價值和成本進行排序,根據使用者所期望的GC停頓時間來制定回收計劃。

現在JVM預設的收集器還不是G1收集器,但可以嘗試。

最後

本文介紹個幾種常見的垃圾收集器。與上文垃圾回收算法對應,建議閱讀《深入了解Java虛拟機》

參考