JVM 运行时数据区域详解
JVM 运行时数据区域通常被称为内存布局,但需注意它与 Java 内存模型(Java Memory Model,简称 JMM)是两个完全不同的概念。它主要由以下 5 大部分组成:

1. 程序计数器(线程私有)
程序计数器的作用很简单:记录当前线程执行的行号。它是一块较小的内存空间,可视为当前线程所执行字节码的行号指示器。
如果当前线程正在执行的是 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是一个 Native 方法,这个计数器值为 undefined。程序计数器是 JVM 规范中唯一没有规定任何 OOM 情况的区域。
在 JVM 中,多线程是通过线程轮流切换来获得 CPU 执行时间的。因此,在任一具体时刻,一个 CPU 内核只会执行一条线程中的指令。为了线程切换后能恢复到正确的执行位置,每个线程都需要有一个独立的程序计数器,且不能互相干扰。
我们通过一段简单的代码及对应的字节码指令来看看程序计数器的实际运作:
public class PcDemo {
public static int add(int a, int b) {
return a + b;
}
}
对应的字节码指令大致如下:
0: iload_0 // 从局部变量表中加载变量 a 到操作数栈
1: iload_1 // 从局部变量表中加载变量 b 到操作数栈
2: iadd // 两数相加
3: ireturn // 返回
执行流程如下:
- 初始状态:当方法开始执行时,PC 计数器设置为 0,指向第一条指令
0: iload_0。 - 执行第一条指令:执行
iload_0指令,将局部变量表中索引为 0 的整数(即方法的第一个参数 a)加载到操作数栈顶。执行完成后,PC 计数器更新为 1,指向下一条指令1: iload_1。 - 执行第二条指令:执行
iload_1指令,将局部变量表中索引为 1 的整数(即方法的第二个参数 b)加载到操作数栈顶。执行完成后,PC 计数器更新为 2,指向下一条指令2: iadd。 - 执行第三条指令:执行
iadd指令,弹出操作数栈顶的两个整数(即 a 和 b),将它们相加,然后将结果压入操作数栈顶。执行完成后,PC 计数器更新为 3,指向下一条指令3: ireturn。 - 执行最后一条指令:执行 指令,弹出操作数栈顶的整数(即 a + b 的结果),并将这个值作为方法的返回值。方法执行完成,控制权返回到方法调用者。



