JVM 將記憶體劃分為線程私有與線程共享兩大類:
| 區域 | 屬性 | 核心功能 | OOM 風險 |
|---|---|---|---|
| 程序計數器 | 線程私有 | 字節碼行號指示器,分支/迴路/線程恢復依賴此計數器 | 無(規範中唯一不拋 OOM 的區域) |
| Java 虛擬機棧 | 線程私有 | 存放棧幀:局部變量表、操作數棧、動態連結、方法出口 | StackOverflowError(遞歸過深)、OOM(線程過多) |
| 本地方法棧 | 線程私有 | 服務 Native 方法,功能與虛擬機棧類似 | 同虛擬機棧 |
| Java 堆 | 線程共享 | 物件實例分配主戰場,GC 主要管理區域,分代:新生代(Eden, S0, S1)、老年代 | OutOfMemoryError: Java heap space |
| 方法區 | 線程共享 | 類資訊、常量、靜態變量、JIT 編譯代碼。JDK 1.7 常量池移至堆,JDK 1.8 元空間取代永久代 | OOM: Metaspace / PermGen space |
+-----------------------+ | 老年代 | <-- 大物件、長期存活物件 +-----------------------+ | 新生代 | | +---+---+---+ | | |Eden|S0 |S1 | | <-- Eden:S0:S1 = 8:1:1 (預設) | +---+---+---+ | +-----------------------+
從 GC Roots 為起點向下搜尋,無引用鏈相連的物件判定為可回收。
GC Roots 包含:
| 參考類型 | 回收時機 | 應用場景 | ||
|---|---|---|---|---|
| 強引用 | 永不回收 | 普遍物件引用 | ||
| 軟引用 | 記憶體不足前 | 快取(圖片、網路資料) | ||
| 弱引用 | GC 運行時 | 快取、監聽器、ThreadLocal | ||
| 虛引用 | 不影響生命週期 | 追蹤物件被回收時機(如直接記憶體釋放) |
| 演算法 | 核心思想 | 優點 | 缺點 | 應用場景 |
|---|---|---|---|---|
| 標記-清除 | 標記可回收 → 統一清除 | 實現簡單 | 效率低、產生記憶體碎片 | 老年代 |
| 複製 | 劃分兩塊,存活物件複製到另一塊 | 無碎片、分配快 | 浪費 50% 空間 | 新生代 (Eden + Survivor) |
| 標記-整理 | 標記 → 存活物件向一端移動 | 無碎片 | 移動開銷大 | 老年代 |
| 問題 | 排查工具/命令 | 關鍵動作 |
|---|---|---|
| 響應緩慢 | jstack、jmap、Arthas、Async Profiler | 分析線程狀態、鎖爭用、CPU 熱點 |
| 頻繁 Full GC | jstat -gc、GC 日誌、GCEasy、Arthas | 分析老年代佔用、大物件直接進老年代、記憶體洩漏 |
| OOM | jmap -heap、MAT、JVisualVM、heap dump | 分析支配者樹、洩漏疑點、歷史堆對比 |
核心工具鏈:
jps→jstack→jmap→jhat/MAT →jstat→Arthas/Async Profiler
建議建立標準化排查 SOP,從現象 → 定位 → 根因 → 修復 → 驗證 → 沉澱。