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

JVM 內存區域劃分深度解析:Eden、Survivor、Tenured、Perm/Metaspace 角色與 GC 流轉機制

     編輯:Java 綜合教學

JVM 內存區域劃分深度解析:Eden、Survivor、Tenured、Perm/Metaspace 角色與 GC 流轉機制

HotSpot JVM 將堆劃分為新生代與老年代,進一步細分為 Eden、Survivor (S0/S1)、Tenured 等區域;非堆區域歷經 PermGen 到 Metaspace 的演進。本文系統梳理各區域職能、對象分配晉升規則、GC 流轉邏輯,並對比 JDK 7/8 關鍵差異。

一、堆內存區域全景圖(JDK 8+)

┌─────────────────────────────────────────────────────────────┐
│                        Heap (堆)                             │
├───────────────────────────┬─────────────────────────────────┤
│      Young Generation     │       Old Generation            │
│      (新生代 / Young)     │       (老年代 / Tenured)        │
├───────────┬───────────────┤                                 │
│  Eden     │  Survivor     │                                 │
│  (伊甸園) │  (倖存區)      │                                 │
│           │  S0 (From)    │                                 │
│           │  S1 (To)      │                                 │
└───────────┴───────────────┴─────────────────────────────────┘

Non-Heap (非堆):
┌─────────────────────┐  ┌─────────────────────┐  ┌──────────────┐
│  Metaspace (元空間) │  │  Code Cache         │  │  Thread Stacks│
│  (類元數據/常量/靜態)│  │  (JIT編譯代碼緩存)   │  │  (Java/本地棧) │
└─────────────────────┘  └─────────────────────┘  └──────────────┘

二、新生代三區詳解

1. Eden Space (伊甸園)

  • 角色:絕大多數對象出生地(`new`、反射、JNI 等)
  • 特點:連續內存空間,指針碰撞分配極快;配合 TLAB (Thread Local Allocation Buffer) 實現無鎖線程本地分配
  • GC 觸發:Eden 滿 → Minor GC (Young GC)
  • 存活率:通常 < 10%,符合「朝生夕死」弱分代假設

2. Survivor Space (倖存區 / S0、S1)

  • 結構:兩塊大小相等區域,輪流充當 From/To,任意時刻一空一用
  • 角色:Minor GC 後存活對象暫存地,經歷多次 GC 仍存活者晉升老年代
  • 流轉邏輯:
    1. Minor GC 時:Eden + From 存活對象 → 復制到 To
    2. 交換 From/To 引用,保證 To 下次為空
    3. 年齡計數器 +1(對象頭標記)
  • 動態年齡判定:若 To 區相同年齡對象總大小 > To 區 50%,直接晉升(無需達到 MaxTenuringThreshold)

3. 分配與晉升核心規則

  1. 優先 Eden 分配:小對象 → Eden + TLAB
  2. 大對象直入老年代:-XX:PretenureSizeThreshold (默認 0 關閉),大數組/長字符串避免復制開銷
  3. 長期存活晉升:年齡 ≥ -XX:MaxTenuringThreshold (默認 15,CMS 為 6)
  4. 空間擔保機制:Minor GC 前檢查老年代連續空間 > 新生代所有對象總大小?否則觸發 Full GC
  5. 動態年齡判定:見上,防止 Survivor 區過早填滿

三、老年代 Tenured Generation

  • 角色:存放長期存活、大對象、晉升對象
  • GC 觸發:老年代空間不足 → Major GC / Full GC
  • 算法選擇:標記-整理 (Parallel Old)、標記-清除 (CMS)、混合收集 (G1)、着色指針 (ZGC)
  • 碎片風險:CMS 標記-清除產生碎片,依賴 -XX:+UseCMSCompactAtFullCollection 定期整理

四、非堆區域演進:PermGen → Metaspace

維度 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

為什麼移除 PermGen?

  1. 難以調優:類元數據大小難預估,PermSize 過小易 OOM,過大浪費堆
  2. 字符串常量池/靜態變量在堆:便於 GC 管理,避免 PermGen 膨脹
  3. 統一工具監控:本地內存可用 NMT (Native Memory Tracking) 監控
  4. 支撐動態語言/類熱部署:類卸載更靈活

五、GC 工作流程全景演示

Minor GC (Young GC) 完整流程

  1. 觸發:Eden 分配失敗
  2. 標記:從 GC Roots 掃描新生代可達對象(需掃描老年代→新生代引用,靠 Card Table)
  3. 復制:Eden + From 存活對象 → 復制到 To
  4. 年齡+1:對象頭年齡計數器遞增
  5. 晉升判定:年齡 ≥ 閾值 或 To 區放不下 → 直接複製到老年代
  6. 清理:Eden、From 區標記為空闲(指針歸零)
  7. 交換:From/To 引用互換,下次 GC 角色反轉

Full GC 觸發條件

  • 老年代空間不足
  • Metaspace 空間不足
  • System.gc() 顯式調用
  • Minor GC 空間擔保失敗
  • CMS 併發模式失敗
  • JDK 8+ 並行收集器自適應調節判斷

六、常見調優參數速查表

參數 含義 建議場景
-Xms / -Xmx 堆初始/最大值 生產環境設為相同,避免震蕩
-Xmn / -XX:NewRatio 新生代大小 / 新老比例 高分配率業務增大新生代
-XX:SurvivorRatio Eden : Survivor 比例 (默認 8:1) 大批量短命對象可調大 Survivor
-XX:MaxTenuringThreshold 晉升年齡閾值 (默認 15) 減少 Full GC 可適當調大
-XX:PretenureSizeThreshold 大對象直入老年代閾值 大數組/緩存對象直入老年代
-XX:MetaspaceSize 元空間初始/GC 觸發閾值 類加載多的應用適當調大
-XX:MaxMetaspaceSize 元空間上限 防止本地內存耗盡必須設置

七、總結

  1. 分代核心:Eden 生成 → Survivor 篩選 → Tenured 安養,針對不同壽命對象選擇最優算法
  2. Survivor 雙區:復制算法無碎片,輪換機制保證一區始終為空
  3. PermGen → Metaspace:本地內存化解 OOM 難題,字符串常量/靜態變量下放堆
  4. 調優本質:根據業務對象壽命分布,調整區域比例、閾值,讓對象「該走的走、該留的留」
  5. 監控關鍵:Young GC 頻率/耗時、老年代增長曲線、Metaspace 佔用、直接內存變化

深刻理解內存區域劃分與流轉機制,是 GC 調優從「玄學」走向「科學」的前提。

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