本篇內容包括:7 種 Jvm 垃圾回收器的介紹、對比 以及 對應的 Jvm 參數設置,這 7 種包括了:Serial、ParNew 以及 Parallel Scavenge 三種新生代回收器 和 :Serial Old、Parallel Old 以及 CMS 三種老年代回收器,此外還有一個 G1 回收器是 Java 目前比較前沿的成果…
一、Jvm 垃圾回收器概述
我們前面提到了,垃圾回收器的 回收的內容、回收的時機以及回收的方式,接下來我們來看 Java 垃圾回收器。如果垃圾回收算法是內存回收的方法論的話,那么垃圾回收器就是內存回收的具體實現了。
Jvm 的垃圾回收器根據場景和實現方式可以分為新生代回收器和老年代回收器,新生代回收器與老年代回收器可以搭配使用。
- 新生代回收器包括:Serial、ParNew 以及 Parallel Scavenge;
- 老年代回收器包括:Serial Old、Parallel Old 以及 CMS;
- 此外,Java7 update 4(第七版第四個更新升級包)之后引入了一個 G1 收集器。
Ps:不同垃圾回收器適合于不同的內存區域,有的兩個垃圾回收器之間也可以配合使用!
二、新生代回收器
1、Serial 收集器
Serial 收集器是最基礎且歷史最悠久的垃圾收集器,作為單線程工作的收集器。Serial 會在它工作時要求暫停用戶所有的其他線程(Stop-the-World 機制)。采用的是 “標記-復制” 算法。垃圾清理時,Serial 回收器不存在線程間的切換,因此,在單 CPU 的環境下,垃圾清除效率比較高。
雖然 Serial 收集器是最基礎最老的收集器,但是迄今為止 HotSpot 虛擬機運行在 Client 模式下的默認的新生代垃圾收集器!相較于其他收集器,Serial 具有以下 3 個優點:
- 簡單高效;
- 所有收集器中額外內存消耗最少;
- 針對內存幾十兆或一兩百兆的新生代,停頓時間能控制在一百毫秒內。
Ps:這里需要注意的一點是 Serial 收集器和 Serial Old 收集器在垃圾收集時不是單線程的,通常所描述的"單線程"是指的垃圾回收時暫停其他所有的工作線程。
2、ParNew 收集器
ParNew 收集器大致可以理解為是 Serial 收集器的多線程版本,因為 ParNew 收集器除了采用并行回收的方式執行內存回收外,與 Serial 收集器之間幾乎沒有任何區別。ParNew 收集器在年輕代中同樣也是采用復制算法、Stop-the-World 機制。
ParNew 收集器是很多版本 Jvm(包括 HotSpot)運行在 Server 模式下新生代的默認垃圾收集器。
ParNew 收集器運行在多 CPU 的環境下,由于可以充分利用多 CPU、多核心等物理硬件資源優勢,可以更快的完成垃圾收集,提升程序的吞吐量。但是在單個 CPU 的環境下,ParNew 收集器不比 Serial 收集器更高效,雖然 Serial 收集器是基于串行回收,但是由于 CPU不需要頻繁的切換,因此可以有效避免多線程交互過程中產生的一些額外開銷。
Ps:除了 Serial 外,目前只有 ParNew GC 能與 CMS 收集器配合工作。
3、Parallel Scavenge 收集器
Parallel Scavenge 收集器同 ParNew 收集器一樣,也是采用 “標記-復制” 算法,且為能夠并行收集的多線程收集器。
Parallel Scavenge 的特點是其關注重點為吞吐量,高吞吐量則可以高效率地利用 CPU 時間,盡快完成程序的運算,但也就是說它的線程單次停止時間可能更長,因此適用于后臺計算型任務程序:
Ps:如果虛擬機完成某個任務,用戶代碼加上垃圾收集總共耗費了 100 分鐘,其中垃圾收集花掉 1 分 鐘,那吞吐量就是 99% :
吞吐量=運行用戶代碼時間/運行用戶代碼時間+運行垃圾回收時間吞吐量=運行用戶代碼時間/運行用戶代碼時間+運行垃圾回收時間 吞吐量=運行用戶代碼時間/運行用戶代碼時間+運行垃圾回收時間
三、老年代回收器
1、Serial Old 收集器
Serial Old 是 Serial 收集器的老年代版本,采用“標記-整理”算法,單線程收集器,也是給 Client 模式下的虛擬機使用。
Ps:在 Jdk1.5 及其以前,它常與 Parallel Scavenge 回收器配合使用,達到較好的吞吐量,另外它也是 CMS 回收器在 Concurrent Mode Failure 時的后備方案。
2、Parallel Old 收集器
Parallel Old 回收器是 Parallel Scavenge 回收器的老生代版本,屬于多線程回收器,采用“標記-整理”算法。Parallel Old 回收器和 Parallel Scavenge 回收器同樣考慮了吞吐量優先這一指標,非常適合那些注重吞吐量和 CPU 資源敏感的場合。
Ps:在注重吞吐量以及 CPU 資源敏感的場合,可以優先考慮 Parallel Scavenge 加 Parallel Old 收集器
3、CMS 收集器
CMS 收集器,是一種以獲取最短回收停頓時間為目標的收集器,其縮寫含義為 Concurrent Mark Sweep,Mark Sweep 指的是“標記-清除”算法,在互聯網網站、B/S 架構的中常用的收集器就是 CMS,因為系統停頓的時間最短,給用戶帶來較好的體驗。
CMS收集器的運作過程分為4個步驟,包括:
- 初始標記(短暫),僅僅只是標記一下 GCRoots 能直接關聯到的對象,速度很快;
- 并發標記(和用戶的應用程序同時進行),進行 GCRoots 追蹤的過程,標記從 GCRoots 開始關聯的所有對象開始遍歷整個可達分析路徑的對象。這個時間比較長,所以采用并發處理(垃圾回收器線程和用戶線程同時工作);
- 重新標記(短暫),為了修正并發標記期間因用戶程序繼續運作而導致標記產生變動的那一部分對象的標記記錄,這個階段的停頓時間一般會比初始標記階段稍長一些,但遠比并發標記的時間短;
- 并發清除(和用戶的應用程序同時進行):垃圾回收
整個過程中耗時最長的并發標記和并發清除過程收集器線程都可以與用戶線程一起工作,所以,從總體上來說,CMS 收集器的內存回收過程是與用戶線程一起并發執行的。
四、G1 收集器
G1(Garbage-First)收集器是最前沿的成果之一,在Java7 update 4之后引入(Jdk7 的第 4 個版本),是一款面向服務端應用的垃圾收集器。在多 CPU 和大內存的場景下有很好的性能。HotSpot 開發團隊賦予它的使命是未來可以替換掉 CMS 收集器。
G1 是一個分代的,增量的,并行與并發的“標記-復制”垃圾回收器。它的設計目標是為了適應現在不斷擴大的內存和不斷增加的處理器數量,進一步降低暫停時間(pause time),同時兼顧良好的吞吐量。
G1收集器的優勢:
-
獨特的分代垃圾回收器,分代GC: 分代收集器,同時兼顧年輕代和老年代;
-
使用分區算法,不要求 eden,年輕代或老年代的空間都連續;
-
并行性: 回收期間,可由多個線程同時工作,有效利用多核cpu資源;
-
空間整理: 回收過程中,會進行適當對象移動,減少空間碎片;
-
可預見性: G1 可選取部分區域進行回收,可以縮小回收范圍,減少全局停頓。
G1收集器的階段分以下幾個步驟:
-
初始標記(它標記了從GC Root開始直接可達的對象);
-
并發標記(從GC Roots開始對堆中對象進行可達性分析,找出存活對象);
-
最終標記(標記那些在并發標記階段發生變化的對象,將被回收);
-
篩選回收(首先對各個Regin的回收價值和成本進行排序,根據用戶所期待的GC停頓時間指定回收計劃,回收一部分Region)。
五、相關知識點
1、HotSpot 的 Server 和 Client 兩種模式
HotSpot 包括 Server 和 Client 兩種模式的實現:
- Java HotSpot Client VM(-client),為在客戶端環境中減少啟動時間而優化;
- Java HotSpot Server VM(-server),為在服務器環境中最大化程序執行速度而設計。
比較:Server VM 啟動比 Client VM 慢,運行比 Client VM 快。Server 模式的運行中,垃圾回收處理做的比較好一些。
2、設置回收器的參數
下面給出配置回收器時,經常使用的參數:
- -XX:+UseSerialGC:在新生代和老年代使用串行收集器
- -XX:+UseParNewGC:在新生代使用并行收集器
- -XX:+UseParallelGC :新生代使用并行回收收集器,更加關注吞吐量
- -XX:+UseParallelOldGC:老年代使用并行回收收集器
- -XX:ParallelGCThreads:設置用于垃圾回收的線程數
- -XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器
- -XX:ParallelCMSThreads:設定CMS的線程數量
- -XX:+UseG1GC:啟用G1垃圾回收器
3、各類回收器總結
回收器 | 回收代 | 回收模式 | 回收算法 | 特點 |
---|---|---|---|---|
Serial | 新生代 | 單線程 | 標記-復制 | 簡單高效,內存消耗少, 停頓時間能控制在一百毫秒內 |
ParNew | 新生代 | 多線程 | 標記-復制 | Serial 的多線程版本 |
Parallel Scavenge | 新生代 | 多線程 | 標記-復制 | 關注重點為吞吐量 |
Serial Old | 老年代 | 單線程 | 標記-整理 | 同 Serial 簡單高效,內存消耗少 |
Parallel Old | 老年代 | 多線程 | 標記-整理 | 同 Parallel Scavenge 適合那些注重吞吐量和 CPU 資源敏感的場合 |
CMS | 老年代 | 多線程 | 標記-清除 | 并發收集、低停頓,但是會產生大量空間碎片、并發階段會降低吞吐量 |
G1 | 多線程 | 標記-復制 | 同時兼顧年輕代和老年代,針對于大 heap |
垃圾回收器的選用決定因素:應用程序的場景、硬件的制約 以及 吞吐量的需求。
- 串行垃圾回收是最簡單的也是效率最低的,如果只是控制臺的單線程程序,簡單任務,并且機器配置不高,推薦使用。
- 并行垃圾回收器是 64bit server 默認的垃圾回收器,一般我們工作和生產上默認不配置,都是并行垃圾回收。對于一般的不要求吞吐的應用,并且硬件資源不是太充足的情況下,并行垃圾回收器差不多能滿足需求。
- CMS 垃圾回收器是對并行垃圾回收器的一個優化,它以 CPU 和系統資源為代價,換取 GC 的延遲。不會一 GC 就 STW,而是根據情況 STW。一定程度上是資源換取速度。
- G1 垃圾回收器是針對于大 heap 的垃圾回收器,如果 heap 分配的足夠大,分的 region 的優先級回收策略會優先清理垃圾多的 region 并且減少了內存空間碎片,分配大對象時不會因為無法找到連續內存空間而提前觸發下一次 GC。