前言
前文对Java运行时数据区的一些基本概念,具体可看理解JVM运行时数据区(一)概念。这篇文章将对运行时数据区的程序计数器做一个深入的了解。
什么是程序计数器
程序计数寄存器(Program Counter Register),也叫程序计数器(PC寄存器)。虽然这边将其称为程序计数寄存器,但是它并不是广义上所指的物理寄存器。因为寄存器是存储指令相关的现场信息,CPU只有把数据装载到寄存器上才能够运行。而JVM中的寄存器不是物理上的寄存器而是对物理寄存器的抽象模拟。这边将其称为程序计数器或许更为贴切。当然,程序计数器也被称为程序钩子。
它是当前线程所执行的字节码行号指示器,在Java虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是控制程序控制流的指示器。
程序计数器的作用
程序计数器的作用只有一个,那就是存储指向下一条指令的地址,也就是即将执行的指令代码地址。上面介绍的时候我们提到字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是控制程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
在java中,任何时间一个线程都只会有一个方法在执行,也就是所谓的当前方法,计数器会存储当前线程正在执行的java方法的JVM指令地址。如果当前执行的是native方法,则计数器里面的值则应为空(undefined),因为程序计数器不负责本地方法栈。
程序计数器的特点
- 它是一块内存空间很小的区域,几乎可以忽略不计,也是运行速度最快的数据区。(与CPU寄存器类似)。
- 线程私有,与线程的生命周期相同。
- 负责记录每个线程当前执行到的位置,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令
- 如果执行本地方法(Native Method),计数器会存储空值(undefined)。
- 不存在垃圾回收,JVM运行时数据区中唯一没有OutOfMemoryError情况的区域。
为什么要设计为线程私有?
因为Java中的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的,在任何一确定的时刻,一个处理器(对于多核处理器来说就是一个内核)都只会执行一条线程中的指令。而在众多线程并发执行期间,会频繁的切换线程,导致线程的中断和恢复。因此需要在线程切换后恢复到正确的执行位置。每条线程都需要又一个独立的程序计数器。各条线程之间的计数器互不影响,独立存储。
简单描述就是:如果是线程共享的,众多线程并发执行期间,线程恢复时没法恢复到上次当前线程中断时执行的指令的位置。
为什么要使用PC寄存器记录下一条指令
因为在多线程并发执行时,恢复到当前线程后,必须要知道接下来要执行那一条指令。
结束语
关于运行时数据区的程序计数器就介绍到这里,下篇将对运行时数据区的Java虚拟机栈进行介绍讲解。文中如有写得不好的地方,请在评论区指出,感谢!