Skip to content

JVM 内存结构

Java 运行时数据区

┌─────────────────────────────────────────────────────────────────┐
│                    JVM 运行时数据区                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   线程共享                                                      │
│   ┌─────────────────────────────────────────────────────────┐  │
│   │                    Heap(堆)                             │  │
│   │   ┌──────────────┐    ┌──────────────┐                 │  │
│   │   │ Eden Space   │    │ Survivor S0  │  Survivor S1     │  │
│   │   │  (伊甸园区)   │    │  (幸存区)    │  (幸存区)       │  │
│   │   └──────────────┘    └──────────────┘                 │  │
│   │         │                                          │      │  │
│   │         ▼                                          ▼      │  │
│   │   ┌─────────────────────────────────────────────────┐    │  │
│   │   │              Old Generation (老年代)               │    │  │
│   │   └─────────────────────────────────────────────────┘    │  │
│   └─────────────────────────────────────────────────────────┘  │
│                                                                  │
│   ┌─────────────────────────────────────────────────────────┐  │
│   │                  Method Area(方法区)                    │  │
│   │   • 类信息 • 常量 • 静态变量 • JIT 编译后代码            │  │
│   └─────────────────────────────────────────────────────────┘  │
│                                                                  │
│   线程私有                                                      │
│   ┌───────────────────┐    ┌───────────────────────────────┐  │
│   │   JVM Stack        │    │    Native Method Stack        │  │
│   │   (虚拟机栈)       │    │    (本地方法栈)                │  │
│   │   • 方法调用       │    │    • native 方法调用           │  │
│   │   • 局部变量       │    │                              │  │
│   └───────────────────┘    └───────────────────────────────┘  │
│                                                                  │
│   ┌───────────────────┐    ┌───────────────────────────────┐  │
│   │   Program Counter │    │    Native Method Interface    │  │
│   │   Register (PC)   │    │    (本地方法接口)              │  │
│   └───────────────────┘    └───────────────────────────────┘  │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

堆(Heap)

堆内存结构

┌─────────────────────────────────────────────────────────────────┐
│                         堆内存结构                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   JDK 7 及之前:                                                  │
│   ┌───────────┬───────────┬───────────────┐                     │
│   │   Eden    │  Survivor │    Old Gen   │                     │
│   │   8/10    │  1/10     │    9/10      │                     │
│   │   (伊甸)  │  (幸存区)  │    (老年代)   │                     │
│   └───────────┴───────────┴───────────────┘                     │
│                                                                  │
│   JDK 8+:                                                        │
│   ┌───────────┬───────────┬───────────────┐                     │
│   │   Eden    │  Survivor │    Old Gen   │                     │
│   │   8/10    │  1/10     │    9/10      │                     │
│   └───────────┴───────────┴───────────────┘                     │
│                        ↓                                        │
│                   Metaspace(元空间)                             │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

堆内存参数

bash
# 初始堆大小
-Xms256m

# 最大堆大小
-Xmx512m

# 新生代大小
-Xmn128m

# Eden 与 Survivor 比例
-XX:SurvivorRatio=8

# 元空间大小(JDK 8+)
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m

虚拟机栈(JVM Stack)

栈帧结构

┌─────────────────────────────────────────────────────────────────┐
│                        栈帧结构                                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   每个线程拥有的栈:                                              │
│   ┌─────────┐                                                   │
│   │ Frame 3 │ ← 当前执行                                        │
│   ├─────────┤                                                   │
│   │ Frame 2 │                                                   │
│   ├─────────┤                                                   │
│   │ Frame 1 │                                                   │
│   └─────────┘                                                   │
│                                                                  │
│   每个栈帧包含:                                                  │
│   ┌─────────────────────┐                                       │
│   │  局部变量表          │  方法参数、局部变量                      │
│   ├─────────────────────┤                                       │
│   │  操作数栈            │  中间运算结果                           │
│   ├─────────────────────┤                                       │
│   │  动态链接            │  指向运行时常量池                        │
│   ├─────────────────────┤                                       │
│   │  返回地址            │  方法返回地址                           │
│   └─────────────────────┘                                       │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

局部变量表

java
public class LocalVarDemo {

    // 实例方法,局部变量表索引 0 是 this
    public void method(int num) {
        int a = 10;           // 索引 1
        String b = "hello";   // 索引 2
        if (num > 0) {
            int c = a + num;  // 索引 3
        }
        // c 在这里已经失效
    }
}

方法区(Method Area)

存储内容

java
class Person {
    private String name;      // 实例变量(存堆)
    private static int count; // 静态变量(存方法区)

    public Person() { }

    public void method() {    // 方法信息(存方法区)
        int a = 10;          // 局部变量(存栈)
    }
}
内容说明
类信息类的修饰符、名称、父类名、接口
字段信息字段修饰符、类型、名称
方法信息方法修饰符、返回值、参数、字节码
常量池符号引用、直接引用
静态变量static 修饰的变量
JIT 编译代码热点代码编译结果

JDK 8+ 变化

┌─────────────────────────────────────────────────────────────────┐
│                    方法区变化                                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   JDK 7 及之前:                                                  │
│   - PermGen(永久代)                                           │
│   - 大小固定,难以调优                                           │
│   - 容易 OOM: PermGen Space                                     │
│                                                                  │
│   JDK 8+:                                                        │
│   - Metaspace(元空间)                                          │
│   - 使用本地内存                                                 │
│   - 大小可动态调整                                               │
│   - 容易 OOM: Metaspace                                         │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

直接内存

NIO 使用

java
// JDK 7+ NIO 使用直接内存
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

// 直接内存不受 -Xmx 控制
// 最大可用 = MaxDirectMemorySize(默认与 -Xmx 相同)

总结

JVM 内存结构核心知识点

区域线程共享存储内容异常
Heap对象实例、数组OOM
Method Area类信息、常量、静态变量OOM(JDK7 PermGen)
JVM Stack局部变量、方法参数SOF、OOM
PC Register当前字节码行号-
Native Stacknative 方法参数SOF、OOM

⚠️ 易错点提醒

  1. 局部变量表索引从 0 开始,实例方法索引 0 是 this
  2. 操作数栈用于方法执行中的中间运算
  3. JDK 8 用 Metaspace 替代 PermGen
  4. 直接内存不受堆大小限制
  5. 每个线程有自己的 JVM Stack 和 PC Register