基于JDK1.8的环境下对JVM的运行时数据区进行一次深入的理解,在JDK1.8之前运行时数据区的整个区域分配如下图所示:
在JDK1.8 之后,方法区就被永远的移除了,取而代之的是一个叫元空间(Meta Space)的内存区域,我就按照JAVA虚拟机规范一个个的对每个区域进行深入的理解
- 程序计数器(The pc Register)
是一块较小的内存空间,但是也运行速度最快的一块内存空间。这块区域也对JAVA的多线程起到了支撑作用。
在JAVA的多线程执行过程中,实际上是线程进行CPU时间片的抢夺来争取执行线程中方法的指令。在多线程的情况下,线程A和线程B进行了资源争夺,在线程A执行了一条指令后,CPU时间片又被线程B争夺到,这个时候如果再切换回线程A,怎么能知道线程A执行到了哪里,又从哪里继续?程序计数器就是做了这么一个工作,记录了线程A的指令执行到了哪里,让CPU可以知道这个线程可以从哪里继续执行下去,所以每一个线程都会有一个自己的程序计数器独立存储,互不影响,随着线程的创建而创建,随着线程的消亡而消亡,这个区域算是线程私有的一个区域。
注:如果程序运行的是JAVA方法,则程序计数器记录的是当前正在执行的虚拟机字节指令的地址。如果是Native方法,则程序计数器的值则为空(undefined),这个区域是Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
程序计数器在JAVA中的体现:
首先我们编写一个JAVA程序:
package utils;
public class Test{
public statici void main(String[] args){
int a = 1;
int b = 2;
System.out.println(a+b);
}
}
将其通过javap -c命令反编译字节码,如下图所示
编译后的test.class 包括一个Test类的默认无参构造器以及一个编写的main方法
Code: 下的
0:iconst_1
1:istore_1
2:iconst_2
3:istore_2
4:getstatic #2
第一列0/1/2 表示这程序计数器的指令地址,iconst_1内容则表示该行指令的具体指令字节码,第三列的#2是符号引用,解析后指向常量池具体引用,在栈帧中也叫动态连接,下文进一步了解这个内容