【JVM進階之路】七:垃圾收集器盤點


在前面,我們已經了解了JVM的分代收集,知道JVM垃圾收集在新生代主要采用標記-復制算法,在老年代主要采用標記-清除標記-整理算法。接下來,我們看一看JDK默認虛擬機HotSpot的一些垃圾收集器的實現。

1、常見垃圾回收器

首先來看一下JDK 11之前全部可用的垃圾收集器。

HotSpot虛擬機

圖中列出了七種垃圾收集器,連線表示可以配合使用,所在區域表示它是屬於新生代收集器或是老年代收集器。

這里還標出了垃圾收集器采用的收集算法,G1收集器比較特殊,整體采用標記-整理算法,局部采用標記-復制算法,后面再細講。

1.1、Serial收集器

Serial收集器是最基礎、歷史最悠久的收集器。

如同它的名字(串行),它是一個單線程工作的收集器,使用一個處理器或一條收集線程去完成垃圾收集工作。並且進行垃圾收集時,必須暫停其他所有工作線程,直到垃圾收集結束——這就是所謂的“Stop The World”。

Serial/Serial Old收集器的運行過程如圖:

Serial/Serial Old收集器運行示意圖

1.2、ParNew收集器

ParNew收集器實質上是Serial收集器的多線程並行版本,使用多條線程進行垃圾收集。

ParNew收集器的工作過程如圖所示:

ParNew/Serial Old收集器運行示意圖

這里值得一提的是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收集器的工作過程如圖:

Serial/Serial Old收集器運行示意圖

1.5、Parallel Old收集器

Parallel Old是Parallel Scavenge收集器的老年代版本,支持多線程並發收集,基於標記-整理算法實現。

Parallel Scavenge/Parallel Old收集器運行示意圖

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收集器運行示意圖如下:

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采用不同的策略去處理。

G1 Heap Regions

這樣就避免了收集整個堆,而是按照若干個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。

G1收集器運行示意圖

相比CMS,G1的優點有很多,可以指定最大停頓時間、分Region的內存布局、按收益動態確定回收集。

只從內存的角度來看,與CMS的“標記-清除”算法不同,G1從整體來看是基於“標記-整理”算法實現的收集器,但從局部(兩個Region 之間)上看又是基於“標記-復制”算法實現,無論如何,這兩種算法都意味着G1運作期間不會產生內存空間碎片,垃圾收集完成之后能提供規整的可用內存。

2、前沿垃圾回收器

2.1、ZGC收集器

在JDK 11當中,加入了實驗性質的ZGC。它的回收耗時平均不到2毫秒。它是一款低停頓高並發的收集器。

與CMS中的ParNew和G1類似,ZGC也采用標記-復制算法,不過ZGC對該算法做了重大改進:ZGC在標記、轉移和重定位階段幾乎都是並發的,這是ZGC實現停頓時間小於10ms目標的最關鍵原因。

ZGC垃圾回收周期

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的探索與實踐


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM