前面我们就讲过,Java 源代码文件经过编译器编译后会生成字节码文件,经过加载器加载完毕后会交给执行引擎执行。在执行的过程中,JVM 会划出来一块空间来存储程序执行期间需要用到的数据,这块空间一般被称为运行时数据区,见下图。
根据 Java 虚拟机规范的规定,运行时数据区可以分为以下几个部分:
- 程序计数器(Program Counter Register)
- Java 虚拟机栈(Java Virtual Machine Stacks)
- 本地方法栈(Native Method Stack)
- 堆(Heap)
- 方法区(Method Area)
JDK 8 开始,永久代被彻底移除,取而代之的是元空间。元空间不再是 JVM 内存的一部分,而是通过本地内存(Native Memory)来实现的。也就是说,JDK 8 开始,方法区的实现就是元空间。
程序计数器
程序计数器(Program Counter Register)所占的内存空间不大,很小很小一块,可以看作是当前线程所执行的字节码指令的行号指示器。字节码解释器会在工作的时候改变这个计数器的值来选取下一条需要执行的字节码指令,像分支、循环、跳转、异常处理、线程恢复等功能都需要依赖这个计数器来完成。
在 JVM 中,多线程是通过线程轮流切换来获得 CPU 执行时间的,因此,在任一具体时刻,一个 CPU 的内核只会执行一条线程中的指令,因此,为了线程切换后能恢复到正确的执行位置,每个线程都需要有一个独立的程序计数器,并且不能互相干扰,否则就会影响到程序的正常执行次序。
也就是说,我们要求程序计数器是线程私有的。
《Java 虚拟机规范》中规定,如果线程执行的是非本地方法,则程序计数器中保存的是当前需要执行的指令地址;如果线程执行的是本地方法,则程序计数器中的值是 undefined。
回复