一、程序计数器
-
def 一块较小的内存空间,可看作当前线程所执行字节码的行号指示器
-
作用 用来存储指向下一条指令的地址,供执行引擎读取
- 直观的说法是,程序计数器用于记录当前代码执行的位置
- 类比物理寄存器的 PC,JVM 中的 PC 寄存器是它的抽象模拟
1. 特点
-
线程私有,生命周期和线程一致
- 每个线程都有其程序计数器,互不影响、独立存储
-
程序控制流的指示器:分支、循环、跳转、异常处理、线程恢复等功能都依赖其完成
-
根据线程正在执行方法的不同,其记录的值不同
- 若为 Java 方法,记录 JVM 字节码指令的地址
- 若为 Native 方法,置空(undefined)
-
唯一没有规定任何
OutOfMemoryError
的区域
2. 相关问题
点击折叠
Q1:为什么程序计数器被设定为线程私有的
A:因为 Java 中的多线程实际上是通过各线程之间轮流切换、分配 CPU 处理时间来实现的,任一确定的时刻,CPU 只执行一条线程中的指令;为了在线程切换后能够恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,其内存区域是线程私有的。
Q2:为什么使用 PC 寄存器记录当前线程的执行地址
A:字节码解释器(interpreter)需要通过改变程序计数器的值,来明确下一条应该执行的字节码指令
二、虚拟机栈
-
def 描述 Java 方法执行时的线程内存模型:每个线程在创建的时候都会创建一个虚拟机栈,其内部保存一个个的栈帧(Stack Frame),对应着一次次的 Java 方法调用
-
作用 主管 Java 程序的运行
1. 特点
-
线程私有,生命周期和线程一致
-
JVM 直接对虚拟机栈进行的操作只有两个:方法执行入栈,执行结束出栈
-
可由线程固定或动态扩展内存大小,不存在垃圾回收问题
- 对固定大小栈,若线程请求分配的栈容量超过 Java 虚拟机栈允许的最大容量,JVM 将抛出
StackOverflowError
异常 - 对动态扩展栈,若没有足够的内存,JVM 将抛出
OutOfMemoryError
异常
- 对固定大小栈,若线程请求分配的栈容量超过 Java 虚拟机栈允许的最大容量,JVM 将抛出
2. 栈帧的构成
-
局部变量表(Local Variables):存储方法参数和定义在方法体内的局部变量,如基本数据类型、对象引用等
- 基本存储单元:局部变量槽(slot),32 位以内的类型占用一个 Slot,64 位的类型占用两个连续的 Slot
-
操作数栈(Operand Stack):在方法执行过程中,根据字节码指令,往操作数栈中写入数据或提取数据,即入栈(push)、出栈(pop)
- 主要用于保存计算的中间结果,并作为计算过程中变量的临时存储空间
-
动态链接(Dynamic Linking):每个栈帧内部均包含一个可指向当前方法所在类的运行时常量池,该栈帧所属方法的引用,以实现动态链接
-
方法返回地址(Return Address):存放调用该方法的程序计数器的值
- 正常返回出口:返回值传递给上层的方法调用者
- 异常返回出口:不产生任何返回值
-
附加信息
3. 相关问题
点击折叠
Q1:栈帧的创建 / 销毁时机
A:当方法被执行时,JVM 会同步创建一个栈帧;方法从调用到执行结束的过程,对应着栈帧在虚拟机栈从入栈到出栈的过程。
Q2:如何访问局部变量表中一个 64bit 的局部变量值
A:JVM 会为局部变量表中的每一个局部变量槽都分配一个访问索引,因为 64bit 的局部变量值占据两个 slot 空间,故应使用该局部变量的前一个索引访问(不能采用任何方式单独访问其中的某一个 Slot)
三、本地方法栈
-
作用 主管本地方法(native method)的调用
1. 特点
-
线程私有,生命周期和线程一致
-
可由线程固定或动态扩展内存大小
- 对固定大小栈,若线程请求分配的栈容量超过 Java 虚拟机栈允许的最大容量,JVM 将抛出
StackOverflowError
异常 - 对动态扩展栈,若没有足够的内存,JVM 将抛出
OutOfMemoryError
异常
- 对固定大小栈,若线程请求分配的栈容量超过 Java 虚拟机栈允许的最大容量,JVM 将抛出
-
optional:不是所有的 JVM 都支持
在 Hotspot JVM 中,本地方法栈和虚拟机栈是合二为一的
2. 本地方法接口,JNI
-
def 一个 Java 调用本地方法的接口
-
作用 提高程序编译效率,并适用于与外部环境交互
本地方法使用 C 实现
四、堆
-
作用 存放对象实例,几乎所有对象实例和数据均在此分配内存
-
注:JDK1.7 后,字符串常量池从方法区移动到了堆中
1. 特点
-
所有线程共享
-
是虚拟机所管理的最大一块内存
五、方法区
-
作用 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器的代码缓存等数据
1. 特点
-
所有线程共享
2. 方法区的构成
-
类信息表
-
运行时常量池
参考资料:
-
《深入理解 Java 虚拟机(第 3 版)》,周志明著