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

JVM 記憶體模型深度解析:堆、棧、方法區、常量池與直接記憶體完整圖譜

     編輯:Java 相關知識

理解 JVM 記憶體結構是排查 OOM、調優 GC、寫出高效能代碼的基石。本文依照 JVM 規範 (JLS/JVMS) 系統梳理運行時資料區劃分、物件分配邏輯、常量池演進與常見誤區。

JVM 運行時資料區總覽 (Java 8+)

+-------------------------+
|       Heap (堆)         |  ← 所有執行緒共享、GC 主戰場、new 物件/陣列分配區
+-------------------------+
|   Metaspace (元空間)    |  ← 類元資料、常量池 (Java 8 移出 Heap)、靜態變數、JIT 代碼緩存
|   (原 PermGen/方法區)   |  ← 本機記憶體、受 MaxMetaspaceFree 控制
+-------------------------+
|  Thread Stacks (棧)     |  ← 每執行緒私有、棧幀存局部變數/操作數棚/方法返回地址
|  (虛擬機棧/本地方法棧)  |  ← -Xss 控制大小、遞歸過深拋 StackOverflowError
+-------------------------+
|  PC Register (程式計數器)| ← 每執行緒私有、指向當前位元碼指令
+-------------------------+
|  Direct Memory (直接記憶體) | ← NIO DirectByteBuffer、Unsafe.allocateMemory、不受 Heap 限制
+-------------------------+

棧 vs 堆:核心差異對照

維度棧堆
存儲內容基本型別局部變數、物件參考、方法調用幀所有 new 出來的物件實例、陣列
執行緒隔離私有共享
生命週期隨方法進出自動入棧/出棧GC 判定不可達才回收
異常StackOverflowErrorOutOfMemoryError: Java heap space
大小控制-Xss (預設 1MB)-Xms/-Xmx
存取速度極快 (指針移動)較慢 (需 GC 管理)

常量池演進史

  • Java 6:常量池在 PermGen (方法區),受 -XX:MaxPermSize 限制,String.intern() 易導致 PermGen OOM
  • Java 7:字串常量池移至 Heap,String.intern() 安全許多
  • Java 8+:PermGen 移除,類元資料進 Metaspace (本機記憶體),常量池隨之遷移

執行時常量池 vs 字串常量池

  • 執行時常量池:每個類一個,存編譯期常量 (字面量、符號引用),載入時進 Metaspace
  • 字串常量池:全域單例,存 String 物件引用,"abc" 字面量編譯期入池,intern() 運行時入池

物件分配流程

  1. new 指令觸發類載入 (未載入則先載入、驗證、準備、解析、初始化)
  2. 在 Heap (TLAB 或共享區) 劃分記憶體
  3. 零值初始化 (非 final 欄位)
  4. 設定對象頭 (Mark Word、Class Pointer、陣列長度)
  5. 執行 <init> 建構子 (賦值、代碼塊)
  6. 返回棧上參考變數指向 Heap 物件地址

常見參數與排查指令

# 查看預設 Heap/Stack 大小
java -XX:+PrintFlagsFinal -version | grep -E 'HeapSize|ThreadStackSize'

# 運行時動態查看
jmap -heap 
jcmd  VM.flags
jstat -gcutil  1000

避坑指南

  • 區分「棧記憶體不足」與「堆記憶體不足」:前者通常是遞歸無出口或大局部變數,後者才是物件洩漏/快取過大
  • String.intern() 在 Java 7+ 安全,但大量動態字串入池仍會撐爆 Heap
  • 直接記憶體 OOM (OutOfMemoryError: Direct buffer memory) 需調 -XX:MaxDirectMemorySize 或檢查 NIO/Netty 未釋放
  • Metaspace OOM 通常是動態生成類過多 (CGLib、JSP、Groovy、Spring AOP)

結語

JVM 記憶體模型不是背誦考點,而是線上故障排查的地圖。熟記各區職責、參數控制、異常特徵,下次遇到 OOM/StackOverflow 才能在幾分鐘內定位根因,而非盲目加記憶體。

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