GC 分代回收 - 垃圾收集器

不要必應發表於2019-09-08

0. 預備知識

0.1 Stop-the-World

  • JVM 由於要執行 GC 而停止了程式的執行
  • 這種情況會在任何一種 GC 演算法中發生
  • 多數 GC 優化通過減少 Stop-the-World 發生的時間來提高程式效能

0.2 Safepoint

在可達性分析中,將所有執行緒都停止,形成一個快照點 (Safepoint),保證了分析結果的確定性

  • 產生 Safepoint 的地方:方法呼叫、迴圈跳轉和異常跳轉等
  • Safepoint 數量要適中

0.3 JVM 執行模式

  • Server
  • Client
    Server 啟動較慢,但是啟動之後的執行速度比 Client 更快
# 檢視 JVM 使用哪種執行模式
$ java -version
java version "1.8.0_221"
Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)
複製程式碼

1. 常見垃圾收集器

GC 分代回收 - 垃圾收集器

1.1 年輕代中常見垃圾收集器

1.1.1 Serial 收集器

  • 單執行緒收集,進行垃圾收集時,會暫停所有工作執行緒
# 指定 GC 使用 Serial (複製演算法)
-XX: +UseSerialGC
複製程式碼

1.1.2 ParNew 收集器

  • 多執行緒收集,其餘與 Serial 一致
  • 單核執行效率不如 Serial,多核下有優勢
# 指定 GC 使用 ParNew (複製演算法)
-XX: +UseParNewGC
複製程式碼

1.1.3 Parallel Scavenge 收集器

吞吐量 = 執行使用者程式碼的時間 / (執行使用者程式碼的時間 + 垃圾回收的時間)

  • 與 ParNew 類似,都使用多執行緒
  • Parallel Scavenge 相對於 ParNew 不同的是,後者更注意使用者執行緒的等待時間,前者則是關注整個系統的吞吐量
  • JVM Server 模式下預設
# 指定 GC 使用 Parallel Scavenge (複製演算法)
-XX: +UseParallelGC
複製程式碼

1.2 常見的老年代收集器

1.2.1 Serial Old 收集器

  • 單執行緒收集,進行垃圾收集時,會暫停所有工作執行緒
  • 簡單高效,Client 模式下預設的老年代收集器
# 指定 GC 使用 Serial Old (標記-整理演算法)
-XX: +UseSerialOldGC
複製程式碼

1.2.2 Parallel Old 收集器

  • 與 Parallel Scavenge 類似,只不過採用的是標記-整理演算法
# 指定 GC 使用 Parallel Old (標記-整理演算法)
-XX: +UseParallelOldGC
複製程式碼

1.2.3 CMS 收集器

  • 清理執行緒和使用者執行緒幾乎能做到同時工作
標記和回收過程 (六步)
  • 初始標記:Stop-the-World
  • 併發標記:併發追溯標記,程式不會停頓
  • 併發預清理:查詢執行併發標記階段從年輕代晉升到老年代的物件
  • 重新標記:暫停虛擬機器 (Stop-the-World),掃描 CMS 堆中的剩餘物件
  • 併發清理:清理垃圾物件,程式不會停頓
  • 併發重置:重置 CMS 收集器的資料結構
# 指定 GC 使用 CMS (標記-清除演算法)
-XX: +UseConcMarkSweepGC
複製程式碼

1.3 年輕代和老年代公用的演算法

1.3.1 G1 收集器

  • 併發和並行
  • 分代收集
  • 空間整合(標記-整理)
  • 可預測的停頓(指定在 M 毫秒內,消耗在 GC 上的時間不得超過 N 毫秒)
工作原理簡述
  • 將 Java 堆記憶體劃分成多個大小相等的 Region
  • 上面的特性導致了,新生代和老年代不再是物理隔離的記憶體空間,他們現在都是一系列 Region 的集合,在邏輯上連續
# 指定 GC 使用 G1 (複製 + 標記-清除演算法)
-XX: +UseG1GC
複製程式碼

相關文章