弱分代假設:絕大多數對象朝生夕死,存活時間短。
強分代假設:熬過越多次 GC 的對象,存活時間越長。
跨代引用假設:跨代引用 (老年代→新生代) 相對較少。
基於此,堆劃分為:新生代、老年代、元空間 (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) +--------------------------+
| 算法 | 原理 | 優點 | 缺點 | 適用區域 |
|---|---|---|---|---|
| 標記-清除 | 標記存活 → 清除死亡 | 實現簡單 | 碎片化、兩次掃描 | 老年代 (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
-XX:MaxGCPauseMillis (停頓目標)、-XX:GCTimeRatio (吞吐目標)InitiatingHeapOccupancyPercent (默認 45%) 觸發,並發標記 + 部分 Region 複製/整理-XX:MaxGCPauseMillis=200 (停頓目標)、-XX:G1HeapRegionSize=16m-XX:+UseZGC -XX:+ZGenerational (分代 ZGC)-Xlog:gc*:file=gc.log:time,uptime,level,tags) + GCViewer/GCEasy 分析。-Xms -Xmx 設相同,避免動態伸縮抖動。預留 20-30% 給 Direct Memory/Metaspace/CodeCache/OS。-XX:NewRatio (G1 不建議固定)、-XX:SurvivorRatio。-XX:PretenureSizeThreshold (非 G1/ZGC)。-XX:MaxTenuringThreshold (默認 15,G1 動態調整)。| 現象 | 可能原因 | 排查與解決 |
|---|---|---|
| 頻繁 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 OOM | Netty/直接緩衝區未釋放、MaxDirectMemorySize 過小 | -XX:MaxDirectMemorySize、檢查 Cleaner/ReferenceQueue |
dashboard、heapdump、gc 實時診斷。GC 調優無銀彈,**理解分代假設、選對收集器、設定合理目標、持續觀測迭代** 是核心。JDK 8 仍用 Parallel/G1;JDK 11-17 推薦 G1 (通用) 或 ZGC (大內存/低延遲);JDK 21+ **優先嘗試 Generational ZGC**。記住:代碼層面減少對象分配、縮短存活周期、避免大對象、修復內存洩漏,往往比調參數收效更大。