Java 記憶體區域:堆與棧深度解析
Java 虛擬機(JVM)執行期間將記憶體劃分為多個區域,其中堆與棧是最核心、最常被討論的兩大區域。理解兩者差異,對排查 OOM、優化效能、理解物件生命週期至關重要。
棧:執行緒私有,方法執行基本單位
- 生命週期:隨執行緒建立而建立,隨執行緒結束而釋放。
- 結構:由棧幀組成,每個方法呼叫對應一個棧幀。
- 棧幀包含:區域變數表、操作數棧、動態連結、方法返回地址。
- 儲存內容:基本型別變數、物件參考(引用)、方法呼叫上下文。
- 特點:存取速度極快(僅次於程式計數器),大小固定或動態擴展,可能拋出
StackOverflowError(遞歸過深)或 OutOfMemoryError(無法擴展)。
堆:執行緒共享,物件實例主要儲存地
- 生命週期:JVM 啟動時建立,關閉時銷毀。
- 核心功能:儲存所有物件實例與陣列(逃逸分析優化後的標量置換除外)。
- 分代結構:新生代 + 老年代(含永久代/元空間),便於垃圾回收器(GC)採用不同演算法。
- 記憶體分配:指標碰撞(規整記憶體)或空閒列表(不規整),TLAB(執行緒本地分配緩衝)提升多執行緒分配效率。
- 異常:空間耗盡拋出
OutOfMemoryError: Java heap space。
核心差異對比表
| 維度 | 堆 | 棧 |
| 共享性 | 全域共享 | 執行緒私有 |
| 儲存內容 | 物件實例、陣列 | 基本型別、引用、棧幀 |
| 管理方式 | GC 自動管理 | 編譯期確定/執行期自動釋放 |
| 分配速度 | 較慢(需 GC 配合) | 極快(指針移動) |
| 空間大小 | 可配置 GB 級 | 預設 1MB/執行緒 |
| 典型異常 | OOM: Heap space | StackOverflowError |
進階補充:方法區、程式計數器、本地方法棧
- 方法區:儲存類別資訊、常數、靜態變數、JIT 編譯代碼。JDK 8 移除永久代,改用元空間(直接記憶體)。
- 程式計數器:當前執行指令地址,執行緒私有,唯一不會 OOM 區域。
- 本地方法棧:服務 Native 方法(C/C++)。
實戰診斷技巧
-Xms -Xmx 設定堆初始/最大值;-Xss 設定棧大小。
- 使用
jmap -histo:live pid、jvisualvm、arthas 分析堆物件分佈。
- 遞歸改迭代、大物件入老年代、減少棧幀大小(少宣告區域變數)優化棧使用。
掌握 JVM 記憶體模型,是從「會用 Java」進階到「懂 JVM」的關鍵門檻。