JVM-内存结构
1. 程序计数器 (Program Counter Register)
- 核心作用:
→ 记录当前线程执行的字节码指令地址(行号指示器)
→ 线程切换后恢复执行的依据 - 关键特性:
✅ 线程私有(每个线程独立)
✅ 唯一无OutOfMemoryError
的区域
✅ 执行Native方法时值为undefined
- 内存占用:
极小的固定空间(通常可忽略)
2. 虚拟机栈 (Java Virtual Machine Stack)
-
核心作用:
→ 存储方法调用的 栈帧(Stack Frame)
→ 栈帧包含四个部分:组成部分 功能 局部变量表 存储方法参数和局部变量(含对象引用 reference
)操作数栈 存放计算过程中的临时数据(如算术运算中间值) 动态链接 指向运行时常量池的方法引用(支持运行时绑定) 方法返回地址 记录方法结束后回到调用位置(正常返回/异常退出) -
关键特性:
✅ 线程私有(栈深度默认1MB)
❗ 抛出StackOverflowError
(如无限递归)
❗ 抛出OutOfMemoryError
(扩展栈空间失败)
3. 本地方法栈 (Native Method Stack)
- 核心作用:
→ 为Native方法(C/C++实现)提供栈空间
→ 存储本地方法的调用信息 - 关键特性:
✅ 线程私有
⚠️ HotSpot 虚拟机中将虚拟机栈与本地方法栈合并实现
❗ 抛出StackOverflowError
/OutOfMemoryError
4. 堆 (Heap)
-
核心作用:
→ 存储所有对象实例和数组 -
内存分区:
- 新生代:新对象分配区(默认占堆1/3)
- 老年代:长期存活对象区(默认占堆2/3)
-
关键特性:
✅ 线程共享(所有线程共享对象访问)
❗ 垃圾回收(GC)主要战场
❗ 抛出OutOfMemoryError: Java heap space
(对象无法分配)
5. 方法区 (Method Area)
-
核心作用:
→ 存储 类信息(字段/方法名)、运行时常量池、静态变量、JIT编译后代码 -
演进历史:
JDK版本 实现 位置 参数 ≤JDK7 永久代 堆内存中 -XX:PermSize
/MaxPermSize
≥JDK8 元空间 本地内存 -XX:MetaspaceSize
-
关键特性:
✅ 线程共享
❗ 抛出OutOfMemoryError: Metaspace
(类元数据过多)
✅ 运行时常量池是方法区的核心部分
常量池体系详解
常量池分为三级结构,关系如下:
1. Class 文件常量池 (Constant Pool)
- 位置:
.class
文件中的固定结构 - 内容:
✅ 字面量:字符串、数值等显式常量
✅ 符号引用:String s = "fly"; // "fly" 即字面量
→ 类/接口的全限定名(如java/lang/Object
)
→ 字段名和描述符(如Ljava/lang/String;
)
→ 方法名和描述符(如()V
) - 特点:
→ 编译期生成
→ 静态存储(不依赖运行时)
2. 运行时常量池 (Runtime Constant Pool)
- 位置:方法区的一部分(JDK8+在元空间)
- 生成过程:
→ 类加载时,将Class文件常量池加载到内存
→ 符号引用 → 解析为 直接引用(指向方法/字段的内存地址) - 动态性:
✅ 支持运行时添加常量(如String.intern()
)
✅ 存储内容:
→ 类/方法解析后的直接引用
→ 数值/字符串等基本常量
3. 字符串常量池 (String Table)
-
位置演变:
JDK版本 位置 原因 JDK6 方法区 受永久代大小限制,易OOM JDK7+ 堆内存 允许GC回收,避免OOM;调优更灵活 -
核心机制:
// 示例1:直接赋值(优先使用常量池) String s1 = "fly"; // 在常量池创建对象 String s2 = "fly"; // 复用常量池对象(s1 == s2)// 示例2:new创建(堆中新对象) String s3 = new String("fly"); // 堆中创建新对象(s1 ≠ s3)// 示例3:intern主动入池 String s4 = s3.intern(); // 返回常量池引用(s1 == s4)
-
设计优势:
✅ 避免重复创建:相同字符串共享内存
✅ GC可回收:JDK7+后可被垃圾回收
常量池对比总结
特性 | Class文件常量池 | 运行时常量池 | 字符串常量池 |
---|---|---|---|
存在阶段 | 编译期(.class文件) | 运行期(方法区/元空间) | 运行期(堆) |
是否可动态添加 | ❌ | ✅(intern等) | ✅(intern强制入池) |
内容 | 字面量+符号引用 | 直接引用+运行时添加的常量 | 唯一字符串的引用 |
内存回收 | 不支持 | JDK8+由元空间管理 | JDK7+支持GC回收 |
OOM风险 | 无 | 元空间溢出 | 堆内存溢出 |