Java学习第七十七部分——JVM运行时数据区
目录
一、前言提要概述
二、核心组件概览
三、详细组件说明
四、内存区域关系图
五、堆内存详细结构——分代模型
五、异常情况示例
六、总结分析
一、前言提要概述
Java 虚拟机(JVM)在运行 Java 程序时,会将内存划分为多个逻辑区域,每个区域有特定的职责。
二、核心组件概览
JVM 运行时数据区主要分为线程私有区和 线程共享区。
区域类型 | 组成部分 | 线程安全 | 异常类型 | 作用描述 |
---|---|---|---|---|
线程私有区 | 程序计数器(PC) | 线程私有 | 无 | 记录当前线程执行的字节码位置 |
虚拟机栈(JVM Stack) | 线程私有 | StackOverflowError OutOfMemoryError | 存储方法调用的栈帧 | |
本地方法栈(Native Stack) | 线程私有 | StackOverflowError OutOfMemoryError | 支持 Native 方法调用 | |
线程共享区 | 堆(Heap) | 线程共享 | OutOfMemoryError | 存储所有对象实例和数组 |
方法区(Method Area) | 线程共享 | OutOfMemoryError | 存储类信息、常量池、静态变量等 | |
运行时常量池(Runtime Constant Pool) | 线程共享 | OutOfMemoryError | 存储字面量和符号引用 |
三、详细组件说明
1. 程序计数器(Program Counter Register)
- **作用**:记录当前线程正在执行的字节码指令地址(分支、循环、跳转等)。
- **特性**:
- 唯一不会发生 `OutOfMemoryError` 的区域。
- 线程私有(每个线程独立存储执行位置)。
- **示例**:若线程执行 `add` 指令,PC 指向该指令的内存地址。
2. 虚拟机栈(JVM Stack)
- **作用**:存储方法调用的栈帧(Stack Frame),每个方法对应一个栈帧。
- **栈帧结构**:
- **局部变量表**:存放方法参数和局部变量(基本类型、对象引用)。
- **操作数栈**:执行字节码指令的工作区(如加减乘除)。
- **动态链接**:指向运行时常量池的方法引用。
- **返回地址**:方法退出后恢复执行的地址。
- **异常**:
- `StackOverflowError`:栈深度超过限制(如无限递归)。
- `OutOfMemoryError`:栈扩展失败(如线程过多)。
3. 本地方法栈(Native Method Stack)
- **作用**:支持 Native 方法(如 C/C++ 实现)的调用。
- **特性**:与虚拟机栈类似,但服务于 JNI(Java Native Interface)。
- **异常**:同虚拟机栈(`StackOverflowError`/`OutOfMemoryError`)。
4. 堆(Heap)
- **作用**:存储所有对象实例和数组(`new` 关键字创建的对象)。
- **内存管理**:
- 由垃圾回收器(GC)自动管理。
- 分为 **新生代**(Young)和 **老年代**(Old):
- **新生代**:Eden + Survivor(S0, S1),新对象在此分配。
- **老年代**:长期存活的对象(经过多次 GC 后存活)。
- **异常**:`OutOfMemoryError`(堆空间不足)。
5. 方法区(Method Area)
- **作用**:存储类元数据(类名、方法、字段)、运行时常量池、静态变量、JIT 编译后的代码。
- **实现演变**:
- **JDK 1.7 前**:永久代(PermGen),位于堆中。
- **JDK 1.8+**:元空间(Metaspace),使用本地内存(不再受 JVM 堆限制)。
- **异常**:`OutOfMemoryError`(元空间耗尽)。
6. 运行时常量池(Runtime Constant Pool)
- **作用**:存储类文件中的常量池表(字面量、符号引用)。
- **特性**:
- 支持动态性(如 `String.intern()` 动态添加常量)。
- 是方法区的一部分。
四、内存区域关系图
五、堆内存详细结构——分代模型
对象分配流程:
1. 新对象分配在Eden区。
2. Eden 满时触发Minor GC:
- 存活对象复制到Survivor(S0/S1)。
- 年龄计数器 +1(每熬过一次 GC)。
3. 年龄达到阈值(默认 15)的对象进入老年代。
4. 老年代满时触发Full GC(速度慢,影响性能)。
五、异常情况示例
1. `StackOverflowError`
void infiniteRecursion() {infiniteRecursion(); // 无限递归,耗尽虚拟机栈}
2. `OutOfMemoryError`
- **堆溢出**:创建大量对象(如 `new byte[1024 * 1024]`)。
- **元空间溢出**:动态生成大量类(如 CGLib 代理)。
六、总结分析
区域 | 存储内容 | 生命周期 | 垃圾回收 |
---|---|---|---|
程序计数器 | 字节码指令地址 | 线程生命周期 | ❌ |
虚拟机栈 | 栈帧(局部变量/操作数) | 方法调用周期 | ❌ |
堆 | 对象实例、数组 | 对象存活周期 | ✅ |
方法区 | 类元数据、常量池 | JVM 运行周期 | ✅(卸载类) |
ps:JDK 1.8 后方法区由元空间(Metaspace)实现,直接使用本地内存,默认无上限(需监控避免耗尽系统内存)。