JVM 內存模型權威指南:七大運行時數據區結構與異常場景
《Java 虛擬機規範》定義了 JVM 運行時數據區,理解各區域職能、線程共享性、異常觸發條件,是排查 OOM、棧溢出、元空間耗盡等生產故障的理論基石。

1. 程序計數器 - 線程私有
- 角色:當前線程執行的字節碼行號指示器。
- 功能:分支、循環、跳轉、異常處理、線程恢復均依賴計數器。
- 特點:唯一不會拋出 OutOfMemoryError的區域;每線程獨立,互不干擾。
2. Java 虛擬機棧 - 線程私有
- 生命周期:與線程同步。
- 棧幀結構:局部變量表、操作數棧、動態鏈接、方法出口。
- 局部變量表:基本類型、對象引用、returnAddress;編譯期確定大小,運行期不變。
- 兩大異常:
StackOverflowError:棧深度超過虛擬機限制(遞歸過深)。
OutOfMemoryError:動態擴展時無法申請足夠內存。
3. 本地方法棧 - 線程私有
- 服務
native 方法,規範未強制實現細節(HotSpot 合併至 Java 棧)。
- 同樣拋出
StackOverflowError 和 OutOfMemoryError。
4. Java 堆 - 線程共享、最大塊
- 核心職責:存放對象實例,幾乎所有對象在這裡分配。
- GC 主戰場:又稱「GC 堆」,分代收集:新生代 + 老年代;新生代再分 Eden、From Survivor、To Survivor。
- 分配優化:TLAB (Thread Local Allocation Buffer) 為線程私有分配緩衝區。
- 物理不連續、邏輯連續即可。
5. 方法區 - 線程共享、非堆
- 存儲內容:類信息、常量、靜態變量、即時編譯器編譯後代碼。
- 規範寬鬆:可不連續、可固定/可擴展、可不實現 GC。
- GC 行為少:主要回收常量池、卸載無用類。
- 異常:內存分配不足拋出
OutOfMemoryError。
- JDK 8+:元空間取代永久代,使用本地內存。
6. 運行時常量池 - 方法區一部分
- Class 文件常量池(字面量、符號引用)加載後進入此區。
- 動態性:運行期可新增常量(如
String.intern())。
- 無法申請內存拋出
OutOfMemoryError。
7. 直接內存 - 非規範定義、但常用
- NIO
DirectByteBuffer 通過 Unsafe.allocateMemory 分配堆外內存。
- 不受堆大小限制,但受本機總內存限制;頻繁使用易導致
OutOfMemoryError。
總結對照表
| 區域 | 線程共享 | 主要異常 | 核心職能 |
| 程序計數器 | 私有 | 無 | 字節碼行號指示 |
| Java 棧 | 私有 | StackOverflowError / OOM | 方法調用幀管理 |
| 本地方法棧 | 私有 | StackOverflowError / OOM | Native 方法支持 |
| Java 堆 | 共享 | OOM | 對象實例分配、GC |
| 方法區 | 共享 | OOM | 類元數據、常量、靜態字段 |
| 運行時常量池 | 共享 | OOM | 符號引用、字面量、動態常量 |
| 直接內存 | 共享 | OOM | NIO 堆外分配、零拷貝 |
掌握此表,JVM 內存故障排查將有的放矢。