他可以看作是当前线程所执行的字节码的行号指示器,用来记录当前线程执行到哪行字节码的位置,为了线程切换后能恢复到正确的执行位置
特点:
- 线程私有
- 如果执行的是Java方法,他记录的是正在执行的虚拟机字节码指令的地址
- 如果是本地方法,则记录值为空(undefined)
- JVM规范中唯一没有规定OutOfMemoryError情况的区域
为什么是线程私有?
为了线程切换后依然能恢复到代码上次执行的地方,每条线程都需要有各自独立的程序计数器
为什么执行Native方法,值为空?
Native方法大多是通过C/C++实现的,并且它没有编译成需要执行的字节码指令,不需要去存储字节码文件的行号
如果执行Native方法时,程序计数器不存储值,那么线程切换后如何恢复原位继续执行?
程序计数器是在抽象的JVM层面上的概念——当执行Java方法时,这个抽象的“pc寄存器”存的是Java字节码的地址。实现上可能有两种形式,一种是相对该方法字节码开始处的偏移量,叫做bytecode index,简称bci;另一种是该Java字节码指令在内存里的地址,叫做bytecode pointer,简称bcp。对native方法而言,它的方法体并不是由Java字节码构成的,自然无法应用上述的“Java字节码地址”的概念。所以JVM规范规定,如果当前执行的方法是native的,那么pc寄存器的值未定义——是什么值都可以。
上面是JVM规范所定义的抽象概念,那么实际实现呢?
Java线程总是需要以某种形式映射到OS线程上。映射模型可以是1:1(原生线程模型)、n:1(绿色线程 / 用户态线程模型)、m:n(混合模型)
以HotSpot VM的实现为例,它目前在大多数平台上都使用1:1模型,也就是每个Java线程都直接映射到一个OS线程上执行。此时,native方法就由原生平台直接执行,并不需要理会抽象的JVM层面上的“pc寄存器”概念——原生的CPU上真正的PC寄存器是怎样就是怎样。就像一个用C或C++写的多线程程序,它在线程切换的时候是怎样的,Java的native方法也就是怎样的