Java 虛擬機 (JVM) 在運行時將管理的內存劃分為若干個數據區域,每個區域有特定用途、生命周期與線程共享性。理解這些區域是排查 OOM、調優 GC、分析堆外內存洩漏的基礎。本文基於 HotSpot JVM(JDK 8+)標準模型,結合圖解逐一拆解。

| 區域 | 線程共享 | 主要內容 | 核心參數 | 異常 |
|---|---|---|---|---|
| 堆 | ✅ 共享 | 對象實例、數組(幾乎所有對象分配在這裡) | -Xms, -Xmx, -Xmn, -XX:SurvivorRatio | OutOfMemoryError: Java heap space |
| 方法區 | ✅ 共享 | 類元信息、常量、靜態變量、即時編譯器代碼緩存 | -XX:MetaspaceSize, -XX:MaxMetaspaceSize (JDK 8+) | OutOfMemoryError: Metaspace |
| 虛擬機棧 | ❌ 私有 | 棧幀(局部變量表、操作數棧、動態鏈接、方法出口) | -Xss (每線程棧大小) | StackOverflowError / OOM |
| 本地方法棧 | ❌ 私有 | Native 方法調用(C/C++ 等) | -XX:NativeStackSize (HotSpot 合併為虛擬機棧) | StackOverflowError / OOM |
| 程序計數器 | ❌ 私有 | 當前線程執行的字節碼行號指示器 | 無參數調整 | 無 OOM(唯一不拋 OOM 區域) |
| 直接內存 | ✅ 共享 | NIO DirectBuffer、Unsafe.allocateMemory、Netty 等堆外分配 | -XX:MaxDirectMemorySize (默認 = -Xmx) | OutOfMemoryError: Direct buffer memory |
-XX:PretenureSizeThreshold) → 長期存活入老年代 (-XX:MaxTenuringThreshold, 默認 15) → 動態年齡判斷。-Xms2g -Xmx2g -Xmn1g -XX:SurvivorRatio=8。生產環境建議 -Xms = -Xmx 避免震盪。-XX:PermSize/MaxPermSize,易 OOM(類加載器洩漏、大量 JSP、CGLIB 動態代理)。-XX:MetaspaceSize(初始觸發 Full GC 閾值)、-XX:MaxMetaspaceSize(上限)。String.intern() 入池在 JDK 7+ 移至堆。-Xss1m 設置棧大小,決定方法調用深度。遞歸過深 → StackOverflowError;線程過多導致總棧內存超限 → OOM。ByteBuffer.allocateDirect()、Unsafe.allocateMemory()、Netty PooledByteBufAllocator 直接向 OS 申請,避免堆內拷貝,提升 I/O 性能。-XX:MaxDirectMemorySize 和物理內存限制。洩漏難排查(不在堆 Dump 中),需用 NMT (Native Memory Tracking) 或 pmap/jcmd 分析。| 版本 | 方法區實現 | 運行時常量池 | 字符串常量池 | 靜態變量 |
|---|---|---|---|---|
| JDK 6 | 永久代 | 永久代 | 永久代 | 永久代 |
| JDK 7 | 永久代 | 永久代 | ➡️ 堆 | 永久代 |
| JDK 8+ | ➡️ 元空間 | ➡️ 元空間 | 堆 | ➡️ 堆 (類對象在堆,static field 跟隨類對象) |