JVM内存模型主要分为以下几个部分,各自负责存储不同的数据内容:
1. 堆(Heap)
- 存储内容:所有对象实例(new创建的对象)和数组。
- 特点:
- 线程共享,是垃圾回收(GC)的主要区域。
- 进一步划分为新生代(Young Generation,包含Eden、Survivor区)和老年代(Old Generation)。
- 异常:
OutOfMemoryError(当堆无法扩展时)。
2. 方法区(Method Area)
- 存储内容:
- 类信息(如类名、方法、字段、访问修饰符等元数据)。
- 运行时常量池(Runtime Constant Pool,包含字面量、符号引用)。
- 静态变量(static变量)、JIT编译后的代码。
- 特点:
- 线程共享,在Java 8前称为“永久代”(PermGen),Java 8后改为元空间(Metaspace)(使用本地内存,不再受JVM堆大小限制)。
- 异常:
OutOfMemoryError(元空间溢出时)。
3. 虚拟机栈(JVM Stack)
- 存储内容:
- 每个方法执行时创建的栈帧(Frame),包含:
- 局部变量表(基本数据类型、对象引用)。
- 操作数栈(执行字节码指令的临时操作数)。
- 动态链接(指向方法区的方法引用)。
- 方法返回地址(方法结束后返回的位置)。
- 每个方法执行时创建的栈帧(Frame),包含:
- 特点:
- 线程私有,生命周期与线程相同。
- 异常:
StackOverflowError(栈深度超过限制,如无限递归)。OutOfMemoryError(扩展栈时无法申请足够内存)。
4. 本地方法栈(Native Method Stack)
- 存储内容:为JVM调用**本地方法(Native方法,如C/C++实现)**服务的栈帧。
- 特点:
- 线程私有,与虚拟机栈类似,但服务于Native方法。
- 异常:同虚拟机栈(
StackOverflowError或OutOfMemoryError)。
5. 程序计数器(Program Counter Register)
- 存储内容:当前线程执行的字节码指令地址(如果是Native方法,则为Undefined)。
- 特点:
- 线程私有,唯一无
OutOfMemoryError的区域。 - 确保线程切换后能恢复到正确执行位置。
- 线程私有,唯一无
扩展:直接内存(Direct Memory)
- 存储内容:通过
NIO的DirectByteBuffer分配的堆外内存(由操作系统管理)。 - 特点:
- 不属于JVM内存模型,但频繁使用可能导致
OutOfMemoryError。
- 不属于JVM内存模型,但频繁使用可能导致
总结:线程共享 vs 线程私有
| 区域 | 线程共享? | 存储内容 | 异常类型 |
|---|---|---|---|
| 堆 | 是 | 对象实例、数组 | OutOfMemoryError |
| 方法区(元空间) | 是 | 类信息、运行时常量池、静态变量 | OutOfMemoryError |
| 虚拟机栈 | 否 | 方法栈帧、局部变量 | StackOverflowError |
| 本地方法栈 | 否 | Native方法栈帧 | StackOverflowError |
| 程序计数器 | 否 | 字节码执行地址 | 无 |
通过理解这些区域的作用和特点,可以更好地诊断内存溢出(OOM)或栈溢出(SOF)问题,并优化JVM参数(如-Xmx、-Xss、-XX:MaxMetaspaceSize)。
1402

被折叠的 条评论
为什么被折叠?



