Appearance
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 Stack | 否 | native 方法参数 | SOF、OOM |
⚠️ 易错点提醒:
- 局部变量表索引从 0 开始,实例方法索引 0 是 this
- 操作数栈用于方法执行中的中间运算
- JDK 8 用 Metaspace 替代 PermGen
- 直接内存不受堆大小限制
- 每个线程有自己的 JVM Stack 和 PC Register