首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JVM 垃圾回收核心原理:分代假設、GC 算法、收集器演進與調優實戰

     編輯:Java 相關知識

分代假設:GC 設計的基石

弱分代假設:絕大多數對象朝生夕死,存活時間短。
強分代假設:熬過越多次 GC 的對象,存活時間越長。
跨代引用假設:跨代引用 (老年代→新生代) 相對較少。

基於此,堆劃分為:新生代、老年代、元空間 (JDK 8+ 替代永久代)。

堆內存結構 (JDK 8+ 默認)

+--------------------------+
|        Heap (Xmx)        |
|  +--------------------+  |
|  |     Young Gen      |  |  ← 新生代 (1/3 ~ 1/4 Heap)
|  |  +--------------+  |  |
|  |  | Eden (80%)   |  |  |  ← 新對象分配區
|  |  +--------------+  |  |
|  |  | S0 (10%) | S1 (10%) |  |  ← Survivor 區 (雙缓冲,輪換)
|  |  +--------------+  |  |
|  +--------------------+  |
|  |      Old Gen       |  |  ← 老年代 (2/3 ~ 3/4 Heap)
|  |  (長期存活對象)     |  |
|  +--------------------+  |
+--------------------------+
|      Metaspace         |  ← 類元數據、常量池、字符串常量池 (Native Memory)
+--------------------------+

GC 核心算法

算法原理優點缺點適用區域
標記-清除標記存活 → 清除死亡實現簡單碎片化、兩次掃描老年代 (CMS 初期)
標記-整理標記存活 → 向一端移動 → 清除邊界外無碎片移動對象需更新引用、STW 長老年代 (Parallel Old, G1 Mixed, ZGC)
複製劃分兩塊,存活複製到另一塊,清空原區極快、無碎片、分配指針碰撞浪費 50% 空間新生代 (Eden → Survivor)
分代收集新生代用複製、老年代用標記-整理/標記-清除綜合最優需處理跨代引用全堆

垃圾收集器演進時間軸

JDK 1.3  Serial GC          (單線程、STW、Client 模式默認)
JDK 1.4  Parallel Scavenge  (新生代並行、吞吐優先)
JDK 1.5  Parallel Old       (老年代並行、吞吐優先)  →  JDK 8 默認 (Parallel GC)
JDK 1.5  CMS                (老年代並發、低延遲、碎片化、浮動垃圾)  →  JDK 9 棄用, JDK 14 移除
JDK 7    G1                 (區域化、可預測停頓、混合收集、Region)  →  JDK 9 默認
JDK 11   ZGC                (可伸縮、亞毫秒停頓、染色指針、負載屏障)  →  JDK 15 生產就緒
JDK 12   Shenandoah         (Red Hat、並發整理、Brooks 指針、無染色)  →  JDK 15 生產就緒
JDK 21   Generational ZGC   (ZGC 分代版、進一步降低延遲)
JDK 21   Generational Shenandoah

主流收集器深度解析

1. Parallel GC (JDK 8 默認) —— 吞吐量優先

  • 新生代:Parallel Scavenge (多線程複製)
  • 老年代:Parallel Old (多線程標記-整理)
  • 目標:-XX:MaxGCPauseMillis (停頓目標)、-XX:GCTimeRatio (吞吐目標)
  • 適用:批處理、科學計算、後台任務,**不適用低延遲服務**

2. G1 (JDK 9-20 默認) —— 均衡之王

  • Region 化:堆劃分 2048 個 Region (1-32MB),邏輯上屬於 Eden/Survivor/Old/Humongous
  • Young GC:並行複製 Eden+Survivor → Survivor/Old
  • Mixed GC:老年代佔比超 InitiatingHeapOccupancyPercent (默認 45%) 觸發,並發標記 + 部分 Region 複製/整理
  • Full GC:退化為 Serial Old (單線程標記-整理),**極力避免**
  • 關鍵參數:-XX:MaxGCPauseMillis=200 (停頓目標)、-XX:G1HeapRegionSize=16m

3. ZGC (JDK 11+ 實驗 → 15+ 生產) —— 低延遲終極形態

  • 染色指針 + 讀屏障:對象引用 64 位高位存狀態 (Finalizable/Remapped/Marked/Marked1/Marked2)
  • 並發階段:掃描根、並發標記、並發重定位、並發重映射,**幾乎全程無 STW**
  • 停頓 < 1ms (通常 < 0.5ms),與堆大小無關 (支持 4TB-16TB)
  • 適用:大內存 (>8GB)、超低延遲 (金融交易、實時遊戲、廣告競價)
  • JDK 21+ 推薦 -XX:+UseZGC -XX:+ZGenerational (分代 ZGC)

4. Shenandoah (Red Hat、OpenJDK) —— 並發整理先鋒

  • Brooks 指針 (轉發指針) + 寫屏障:對象頭存轉發指針,移動時更新
  • 並發標記、並發清理、並發整理 (無需染色、無讀屏障開銷)
  • 停頓 < 10ms,堆 100GB+ 表現優異
  • JDK 12+ 實驗,JDK 15+ 生產,JDK 21+ 分代版

GC 調優實戰四步法

  1. 確定目標:吞吐優先 (Parallel) vs 低延遲 (G1/ZGC/Shenandoah) vs 小內存 (Serial)。
  2. 基線測試:壓測 + GC 日誌 (-Xlog:gc*:file=gc.log:time,uptime,level,tags) + GCViewer/GCEasy 分析。
  3. 調整參數:
    • 堆大小:-Xms -Xmx 設相同,避免動態伸縮抖動。預留 20-30% 給 Direct Memory/Metaspace/CodeCache/OS。
    • 新生代/老年代比:-XX:NewRatio (G1 不建議固定)、-XX:SurvivorRatio。
    • 大對象直入老年代:-XX:PretenureSizeThreshold (非 G1/ZGC)。
    • 提前晋升阈值:-XX:MaxTenuringThreshold (默認 15,G1 動態調整)。
  4. 驗證與迭代:再次壓測,對比停頓分布、吞吐、CPU、內存佔用。關注 P99/P999 停頓 而非平均值。

常見 GC 問題診斷

現象可能原因排查與解決
頻繁 Young GC、耗時長Eden 太小、分配速率高、大對象多增大 -Xmn 或 -Xmx、優化代碼減少分配、PretenureSizeThreshold
老年代快速增長、頻繁 Full GC內存洩漏、過早晋升、大對象直入老年代MAT 分析 Heap Dump、調大 Survivor、檢查大對象分配點
CMS/G1 碎片化導致 Full GC浮動垃圾、內存碎片、Humongous 區不足G1: 調大 Region、InitiatingHeapOccupancyPercent;ZGC/Shenandoah 根治
Metaspace OOM類加載器洩漏、動態生成類 (CGLIB/動態代理)、字符串常量池過大-XX:MaxMetaspaceSize、排查類加載器、-XX:StringTableSize
Direct Memory OOMNetty/直接緩衝區未釋放、MaxDirectMemorySize 過小-XX:MaxDirectMemorySize、檢查 Cleaner/ReferenceQueue

GC 日誌分析利器

  • GCViewer:可視化停頓、吞吐、內存曲線。
  • GCEasy (在線):上傳日誌自動生成報告、建議。
  • Arthas:dashboard、heapdump、gc 實時診斷。
  • JFR + JMC:JDK Flight Recorder 事件級分析、零侵入。

總結

GC 調優無銀彈,**理解分代假設、選對收集器、設定合理目標、持續觀測迭代** 是核心。JDK 8 仍用 Parallel/G1;JDK 11-17 推薦 G1 (通用) 或 ZGC (大內存/低延遲);JDK 21+ **優先嘗試 Generational ZGC**。記住:代碼層面減少對象分配、縮短存活周期、避免大對象、修復內存洩漏,往往比調參數收效更大。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved