程序计数器
程序计数器 (Program Counter Register) 是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器,存储的下一条将要执行的字节码指令的内存地址,在 Java 虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器;分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成
由于 Java 虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都会执行一条线程中的指令,因此为了线程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为线程私有的内存
如果线程正在执行的是一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是本地(Native)方法,这个计数器的值则应为空(Undefined),此内存区域是唯一一个在 <<Java 虚拟机规范>> 中没有规定任何 OutOfMemoryError 情况的区域
示例:
public class PCRegisterDemo {
public static void main(String[] args) {
int i = 10;
int j = i++ + ++i;
System.out.println(i);
System.out.println(j);
}
}
通过 javap -verbose PCRegister.class 命令进行反解析,下面这些标红的数字就是字节码指令的指示器,通过改变 PC 寄存器的值来选取下一条将要执行的字节码指令
注意: javap 命令并不是反编译,因为 .class 文件本身是一些二进制的字节流,只不过通过 javap 命令解析之后,将这些二进制的流转变成了我们能够看得懂的新衣而已
总结:
PC 寄存器的作用是什么
PC 寄存器是当前线程所执行的字节码的行号指示器,通过改变 PC 寄存器的值可以用来选取下一条将要执行的字节码指令
为什么设置成线程私有
多线程环境下,某个线程如果要进行 CPU 切换,就必须先保存当前的运行环境,等重新获取 CPU 执行权的时候,又要恢复到切换前的环境,这个时候就需要有一个地方记录这个线程切换前,程序执行到了哪个位置,恢复时就从这个位置开始往后执行就可以,如果 PC 寄存器是所有线程共享的,那么就无法正确恢复切换前的运行环境
PC 寄存器为什么不会有 OutOfMemoryError 发生
PC 寄存器存放的是下一条将要执行的字节码指令的地址,Java 虚拟机规范中肯定定义了一条指令地址的最大长度是多少,只要将 PC 寄存器的容量设置成 >= 字节码指令地址的最大长度,就永远不会有 OutOfMemoryError 发生