HotSpot JVM 將堆劃分為新生代與老年代,進一步細分為 Eden、Survivor (S0/S1)、Tenured 等區域;非堆區域歷經 PermGen 到 Metaspace 的演進。本文系統梳理各區域職能、對象分配晉升規則、GC 流轉邏輯,並對比 JDK 7/8 關鍵差異。
┌─────────────────────────────────────────────────────────────┐ │ Heap (堆) │ ├───────────────────────────┬─────────────────────────────────┤ │ Young Generation │ Old Generation │ │ (新生代 / Young) │ (老年代 / Tenured) │ ├───────────┬───────────────┤ │ │ Eden │ Survivor │ │ │ (伊甸園) │ (倖存區) │ │ │ │ S0 (From) │ │ │ │ S1 (To) │ │ └───────────┴───────────────┴─────────────────────────────────┘ Non-Heap (非堆): ┌─────────────────────┐ ┌─────────────────────┐ ┌──────────────┐ │ Metaspace (元空間) │ │ Code Cache │ │ Thread Stacks│ │ (類元數據/常量/靜態)│ │ (JIT編譯代碼緩存) │ │ (Java/本地棧) │ └─────────────────────┘ └─────────────────────┘ └──────────────┘
-XX:PretenureSizeThreshold (默認 0 關閉),大數組/長字符串避免復制開銷-XX:MaxTenuringThreshold (默認 15,CMS 為 6)-XX:+UseCMSCompactAtFullCollection 定期整理| 維度 | PermGen (JDK 7 及之前) | Metaspace (JDK 8+) |
|---|---|---|
| 存儲位置 | 堆內 (受 -XX:MaxPermSize 限制) |
本地內存 (Native Memory,受 -XX:MaxMetaspaceSize 限制,默認無上限) |
| 存儲內容 | 類元數據、常量池、靜態變量、符號引用 | 類元數據、符號引用;字符串常量池、靜態變量移至堆 |
| OOM 風險 | 易發生 java.lang.OutOfMemoryError: PermGen space |
轉移至本地內存 OOM,需監控 Metaspace 佔用 |
| GC 行為 | Full GC 時回收卸載類 | 獨立 GC 週期,類卸載條件更嚴格 |
| 調優參數 | -XX:PermSize, -XX:MaxPermSize |
-XX:MetaspaceSize (初始/觸發 GC 閾值), -XX:MaxMetaspaceSize |
System.gc() 顯式調用| 參數 | 含義 | 建議場景 |
|---|---|---|
-Xms / -Xmx |
堆初始/最大值 | 生產環境設為相同,避免震蕩 |
-Xmn / -XX:NewRatio |
新生代大小 / 新老比例 | 高分配率業務增大新生代 |
-XX:SurvivorRatio |
Eden : Survivor 比例 (默認 8:1) | 大批量短命對象可調大 Survivor |
-XX:MaxTenuringThreshold |
晉升年齡閾值 (默認 15) | 減少 Full GC 可適當調大 |
-XX:PretenureSizeThreshold |
大對象直入老年代閾值 | 大數組/緩存對象直入老年代 |
-XX:MetaspaceSize |
元空間初始/GC 觸發閾值 | 類加載多的應用適當調大 |
-XX:MaxMetaspaceSize |
元空間上限 | 防止本地內存耗盡必須設置 |
深刻理解內存區域劃分與流轉機制,是 GC 調優從「玄學」走向「科學」的前提。