為什麼要分代?
核心假設:**弱代際假說** —— 「大多數對象朝生夕死,少數對象長期存活」。
- **短命對象**:請求參數、臨時變量、String 構建中間對象等,生命週期極短。
- **長命對象**:Session、線程池、緩存、連接池、配置類等,隨應用生命週期。
若不分代,每次 GC 掃描全堆,**長命對象被反覆掃描卻從不回收**,極大浪費 CPU。分代將不同壽命對象隔離,**針對性算法**大幅提效。
堆內存分代佈局

新生代
- **Eden 區**:所有新對象誕生地(TLAB 線程本地分配緩衝優化)。
- **兩個 Survivor 區 (S0, S1)**:對稱、互換角色,**始終有一個為空**。
- **流程**:
- Eden 滿 → Minor GC → 存活對象複製到 S0。
- 下次 Minor GC → Eden + S0 存活對象複製到 S1(S0 清空)。
- 反覆輪換,經歷
MaxTenuringThreshold 次仍存活 → 晉升老年代。
- **動態年齡判定**:若 Survivor 區同齡對象總大小 > Survivor 容量 50%,直接晉升(不等年齡閾值)。
老年代
- 存放**多次 Minor GC 仍存活**的對象、大對象(直接分配)、長期引用對象。
- 回收算法:**標記-清除** 或 **標記-整理**(CMS 為前者,Parallel Old/G1 為後者)。
永久代 / 元空間
- 存放 **Class 元數據、方法、常量池、靜態變量** 等。
- JDK 8 移除永久代,改用**本地內存**實現的 **Metaspace**,默認無上限(受物理內存限制),可用
-XX:MaxMetaspaceSize 限制。
- 動態生成類(JSP、反射、CGLIB、OSGi)易導致 OOM,需監控與調大。
GC 觸發條件分類
Minor GC (Scavenge GC)
- **觸發**:Eden 區分配失敗(空間不足)。
- **範圍**:僅掃描新生代 (Eden + Survivor)。
- **特點**:頻繁、快速、高效(複製算法、存活少)。
Full GC (Major GC)
- **觸發條件**(任一):
- 老年代 (Tenured) 寫滿。
- 永久代/元空間 寫滿。
System.gc() 顯式調用(建議禁用,改用 -XX:+DisableExplicitGC)。
- 堆內存分配策略動態調整(如 CMS 晋升失敗、G1 混合收集失敗)。
- **範圍**:全堆 (Young + Old + Perm/Metaspace)。
- **特點**:耗時長(秒級),**調優核心目標 = 減少 Full GC 頻率與停頓**。