JVM运行时数据区 |程序计数器介绍与分析
文章目录
- 一、程序计数器介绍
- 二、程序计数器代码演示
- 三、关于PC寄存器的两个常见问题
- 1.使用PC寄存器存储字节码指令地址有什么用?
- 2.PC寄存器为什么是线程私有的?
一、程序计数器介绍
JVM中的程序计数器(Program Counter Register),也可以翻译为PC寄存器。这里的程序计数器并非广义上指的物理寄存器,即与cpu中的寄存器不同。寄存器存储指令相关的现场信息,cpu只有把数据装载到寄存器才能运行;而JVM中的程序计数器是对物理PC寄存器的一种抽象模拟
。
- PC寄存器是一块很小的内存空间,几乎可以忽略不计,也是
运行速度最快
的存储区域。 - 在JVM规范中,每个线程都有它自己的程序计数器,是
线程私有
的,生命周期依赖线程。 任何时间一个线程都只有一个方法在执行
,即当前方法。程序计数器会存储当前线程正在执行的Java方法的JVM指令地址(注意:一个方法中有多条指令);如果是在执行native方法,则是未指定值(undefined)。- PC寄存器是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
- 字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。
- PC寄存器是唯一一个在Java虚拟机规范中没有规定任何
OutOfMemoryError
情况的区域。
JVM中每个线程会有一个PC寄存器,指令被分配在不同的栈中,一个栈帧对应一个方法。上图中,依次入栈,在1方法中调用2方法,在2方法中调用到n方法,n又调用到当前栈帧对应的方法。
当前栈帧中,具体的指令有行号标识,PC寄存器就是记录了下一条指令的地址,执行引擎不断的通过PC寄存器来获取下一条指令,进行执行。相当于PC寄存器记录了当前栈帧执行指令的下一条指令的行号
。
二、程序计数器代码演示
以一段简单的代码为例,尝试对其进行反编译:
package com.gql.java;
/** * PC寄存器测试 @author Hudie @date 2020/7/28 - 22:19 */
public class PCRegisterTest {
public static void main(String[] args) {
int i = 10;
int j = 20;
int k = i + j;
String s = "abc";
System.out.println(i);
System.out.println(k);
}
}
反编译后的结果如下,其中PC寄存器指向的就是指令地址。
以其中任意一条指令地址为例,执行引擎
读取PC寄存器
指向的下一条指令地址对应的操作指令,将该条操作指令保存到局部变量表中。然后执行引擎会操作局部变量表、操作数栈。还会将字节码指令翻译成机器指令,进而传递到cpu进行运算。
三、关于PC寄存器的两个常见问题
1.使用PC寄存器存储字节码指令地址有什么用?
因为cpu需要不停的切换各个线程,再次切换回来时,就需要知道接着从哪儿开始继续执行。即JVM的字节码解释器需要通过改变PC寄存器的值来明确下一条应该执行什么样的字节码指令。
2.PC寄存器为什么是线程私有的?
所谓的多线程在一个特定的时间段内只会执行其中某一个线程的方法,CPU会不停的做任务切换,这样必然会导致经常中断或恢复。为了能够准确地记录各个线程正在执行的当前字节码指令地址,最好的办法是为每一个线程都分配一个PC寄存器
,这样一来各个线程之间便可以进行独立计算,从而不会出现相互干扰的情况。
还没有评论,来说两句吧...