Java 虛擬機(JVM)在執行程式時,將管理的記憶體劃分為若干個資料區域。這些區域各有專屬用途、生命週期與執行緒共享特性。深入理解這些區域,不僅是面試必考題,更是排查 OOM(OutOfMemoryError)、效能調優與記憶體洩漏分析的基石。
根據《Java 虛擬機規範》,JVM 管理的記憶體包含以下五大核心區域:
其中,「運行時常量池」屬於方法區的一部分。
定位:當前執行緒所執行的字節碼行號指示器。
核心作用:Java 多執行緒透過時間片輪轉方式實現併發。為了讓執行緒在切換後能精確恢復到正確執行位置,每條執行緒都需要一個獨立的程式計數器,互不干擾,屬於「執行緒私有」記憶體。
特殊性:唯一在 JVM 規範中不會拋出 OutOfMemoryError 的區域。
定位:描述 Java 方法執行的記憶體模型。
基本單位 - 幀框架:每個方法被執行時,JVM 會同步建立一個棧幀,用於儲存:
記憶體分配時機:區域變數表所需記憶體空間在編譯期即已確定,進入方法時直接分配。
異常情況:
StackOverflowError:請求深度超過最大深度OutOfMemoryError:無法申請到足夠記憶體(動態擴展失敗)與虛擬機堆疊極度相似,差別在於服務對象:虛擬機堆疊服務 Java 方法,本地方法堆疊服務 native 方法。部分 JVM(如 HotSpot)將兩者合併實作。
核心地位:JVM 管理的最大記憶體區域,虛擬機啟動時建立,所有執行緒共享。
唯一目的:儲存物件實例(幾乎所有物件實例與陣列都在這裡分配)。
物理特性:可處於不連續的物理記憶體空間,只需邏輯上連續即可。支援透過 -Xms/-Xmx 設定初始/最大容量。
GC 主戰場:現代收集器採用分代演算法,堆進一步細分為新生代、老年代等區域。
共享特性:與堆同樣為執行緒共享區域。
儲存內容:
演進歷程:
PermGen space OOM屬於方法區一部分。Class 檔案中的常量池編譯期生成,類別載入後進入方法區的運行時常量池。具備動態性:執行期間可透過 String.intern() 等方式放入新常數。
| 區域 | 共享性 | 主要內容 | 典型異常 |
|---|---|---|---|
| 程式計數器 | 執行緒私有 | 字節碼行號 | 無 OOM |
| 虛擬機堆疊 | 執行緒私有 | 棧幀(區域變數、運算元堆疊...) | StackOverflowError / OOM |
| 本地方法堆疊 | 執行緒私有 | Native 方法棧幀 | StackOverflowError / OOM |
| Java 堆 | 全域共享 | 物件實例、陣列 | OOM (Heap Space) |
| 方法區 | 全域共享 | 類資訊、常數、靜態變數、JIT 程式碼 | OOM (Metaspace/PermGen) |
-XX:+PrintFlagsFinal 查看預設記憶體參數jmap -heap、jstat -gc 監控堆/方法區使用率