全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-11 7 分钟 ✍️ juanwangdev

Java JVM内存结构

JVM运行时数据区是程序运行的数据存储区域,不同区域有不同用途。

JVM内存区域划分

Java
┌─────────────────────────────────────────────────┐
│                运行时数据区                       │
├─────────────────────────────────────────────────┤
│  ┌─────────────────┐  ┌─────────────────┐      │
│  │   程序计数器     │  │   Java栈        │      │
│  │   (线程私有)     │  │   (线程私有)     │      │
│  └─────────────────┘  └─────────────────┘      │
│  ┌─────────────────┐  ┌─────────────────┐      │
│  │   本地方法栈     │  │   方法区/元空间  │      │
│  │   (线程私有)     │  │   (线程共享)     │      │
│  └─────────────────┘  └─────────────────┘      │
│  ┌─────────────────────────────────────────┐   │
│  │                  堆                       │   │
│  │               (线程共享)                  │   │
│  │    ┌─────────┬─────────┬─────────┐      │   │
│  │    │ 年轻代   │  年老代 │ 元空间  │      │   │
│  │    │Eden+Surv│        │(JDK8+) │      │   │
│  │    └─────────┴─────────┴─────────┘      │   │
│  └─────────────────────────────────────────┘   │
└─────────────────────────────────────────────────┘

各内存区域详解

1. 程序计数器

作用:记录当前线程执行到哪条字节码指令。

Java
// 多线程执行时,每个线程有独立的程序计数器
// 纰程切换后能恢复到正确的执行位置

特点

  • 线程私有
  • 唯一不会OOM的区域
  • 执行native方法时为空

2. Java栈

作用:存储方法调用和局部变量。

Java
public int add(int a, int b) {
    int sum = a + b;  // 局部变量在栈帧中
    return sum;
}

栈帧结构

Java
┌─────────────┐
│   栈帧      │
├─────────────┤
│ 局部变量表   │ ← 方法参数、局部变量
│ 操作数栈    │ ← 计算中间结果
│ 动态链接    │ ← 方法引用
│ 返回地址    │ ← 方法返回位置
└─────────────┘

特点

  • 线程私有
  • 栈溢出:StackOverflowError(递归过深)
  • OOM:OutOfMemoryError(创建过多线程)

3. 本地方法栈

作用:执行本地方法(Native Method)。

Java
// Thread.java中的本地方法
private native void start0();

特点

  • 线程私有
  • 与Java栈类似,但执行本地方法

4. 堆

作用:存储对象实例和数组。

Java
Object obj = new Object();  // 对象在堆中
int[] arr = new int[100];   // 数组在堆中

堆结构

Bash
┌───────────────────────────────────────┐
│                 堆                     │
├───────────────────────────────────────┤
│  ┌─────────────────────────────┐     │
│  │      年轻代(Young Gen)      │     │
│  │  ┌───────┬───────┬───────┐  │     │
│  │  │ Eden  │ S0    │ S1    │  │     │
│  │  │       │Survivor│Survivor│  │     │
│  │  └───────┴───────┴───────┘  │     │
│  └─────────────────────────────┘     │
│  ┌─────────────────────────────┐     │
│  │      老年代(Old Gen)       │     │
│  └─────────────────────────────┘     │
└───────────────────────────────────────┘

特点

  • 线程共享
  • GC主要区域
  • 可设置大小:-Xms、-Xmx

5. 方法区/元空间

作用:存储类信息、常量、静态变量。

text
public class MyClass {
    private static int count;      // 静态变量在方法区
    private static final int MAX;  // 常量在方法区
}

存储内容

  • 类信息:类名、父类、接口、方法
  • 运行时常量池:字符串常量、符号引用
  • 静态变量
  • JIT编译后的代码

演变

JDK版本名称位置
JDK 7永久代JVM堆的一部分
JDK 8+元空间本地内存

特点

  • 线程共享
  • JDK 8+使用元空间,不再受堆大小限制

直接内存

作用:NIO使用的堆外内存。

text
// NIO直接缓冲区
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

特点

  • 不受JVM堆大小限制
  • 减少GC压力
  • 分配/释放开销较大

内存区域对比

区域线程归属存储内容GC异常
程序计数器私有指令位置
Java栈私有栈帧StackOverflowError
本地方法栈私有本地方法栈帧StackOverflowError
共享对象OutOfMemoryError
方法区共享类信息有(JDK8+)OutOfMemoryError

JVM内存参数

text
# 堆大小
-Xms512m    # 初始堆大小
-Xmx1024m   # 最大堆大小

# 年轻代
-Xmn256m    # 年轻代大小
-XX:SurvivorRatio=8  # Eden:S0:S1比例

# 元空间
-XX:MetaspaceSize=128m  # 元空间初始大小
-XX:MaxMetaspaceSize=256m  # 元空间最大大小

# 栈大小
-Xss256k    # 每个线程栈大小

注意事项

堆是GC主要区域,优化重点

方法区/元空间存储类信息,类太多会OOM

栈深度过大会StackOverflowError

直接内存不在堆中,但受-XX:MaxDirectMemorySize限制

要点总结

  1. JVM内存区域:程序计数器、Java栈、本地方法栈、堆、方法区
  2. 程序计数器、栈是线程私有;堆、方法区是线程共享
  3. 堆存储对象,是GC主要区域
  4. 方法区存储类信息,JDK 8+改为元空间
  5. 合理设置-Xms、-Xmx、-Xmn等参数优化内存

📝 发现内容有误?点击此处直接编辑

← 上一篇 锁机制(ReentrantLock 等)
下一篇 → Java JVM概述与跨平台原理
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库