深入理解 Java 虚拟机之 JVM 内存
Java 内存区域
程序计数器(Program Counter Register
)
- 当前线程执行字节码的行号计数器。字节码解释器工作时通过改变该计数器的值来获取下一条需要执行的字节码指令。常见的功能比如:分支、循环、异常处理、线程恢复等。线程私有。
- 如果当前线程执行的是一个 Java 方法,该计数器记录正在执行的字节码指令的地址;如果是 Native 方法,则该计数器为空(undefined)。同时也是JVM规范中唯一一个没有规定 OOM 情况的区域
虚拟机栈(Java Virtual Machine Stacks
)
- 虚拟机栈描述的是 Java 中方法执行的内存模型。每个方法在执行时会创建一个栈帧(
Stack Frame
)用来存储局部变量表、操作数栈、动态链接、方法出口等相关信息。 - JVM规范中对此区域规定了两种异常情况:
- 如果线程栈深度大于JVM允许的深度时,会出现
Stack Overflow Error
- 如果在动态扩展时无法申请到足够的内存时,会出现
Out of Memory Error
- 如果线程栈深度大于JVM允许的深度时,会出现
本地方法栈(Native Method Stack
)
- 与虚拟机栈作用类似,只是这里是为Java Native 方法服务
- 可能出现的异常同虚拟机栈一样
堆(Heap
)
- 线程共享
- 主要存放对象实例及数组
方法区(Method Area
)
- 线程共享
- 主要存放类的信息、常量、静态变量、
JIT
编译后的代码等 - 常量池(
Runtime Constant Pool
)- 常量池是方法区的一部分
- 主要存放编译期产生的字面量及符号引用
对象的创建
对象的内存布局
对象头(Header
)
-
Mark Word
存储对象本身的运行时数据(HashCode、GC分代年龄、锁状态标志、线程持有的锁、锁偏向线程的ID、偏向时间)
-
类型指针
通过该指针确定对象是哪个类的实例
当对象是数组时,还会记录数组的长度
实例数据(Instance Data
)
- 对象中的各种字段
对齐填充(Padding
)
- 由于
HotSpot VM
的自动内存管理系统要求对象的大小必须是8字节的整数倍。一般对象头会是8字节的倍数(1倍或2倍),所以当实例数据不满足此要求时,就需要对齐填充。