JVM学习笔记三:运行时数据区之程序计数器

Posted 算不出来没办法

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM学习笔记三:运行时数据区之程序计数器相关的知识,希望对你有一定的参考价值。

目录

概述

字节码取指令举例 

CPU时间片

经典问题

使用PC寄存器存储字节码指令地址有什么用呢?

为什么使用PC寄存器记录当前线程的执行地址呢?


概述

运行时数据区中运行速度最快的存储区域,并且是线程私有的,每一个线程都具有自己的程序计数器,生命周期与线程的生命周期保持一致。

程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。在Java虛拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。由于Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的(也就是时间片分配),在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。 因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有“的内存。如果线程正在执行的是一个Java方法, 这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是本地(Native) 方法,这个计数器值则应为空(Undefined) 。此内存区域是唯一一个 在《Java虚拟机规范》中没有规定任何OutOfMemoryError情况的区域。(出自《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》)

字节码取指令举例 

public class Main 
    public static void main(String[] args) 
        int a = 1;
        int b = 3;
        int c = a + b;
        System.out.println(c);
    

上面这一段简单的代码对应的字节码文件如下:

 0 iconst_1
 1 istore_1
 2 iconst_3
 3 istore_2
 4 iload_1
 5 iload_2
 6 iadd
 7 istore_3
 8 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
11 iload_3
12 invokevirtual #3 <java/io/PrintStream.println : (I)V>
15 return

而程序计数器所做的事情就是取上面的指令并执行。

CPU时间片

CPU时间片即CPU分配给各个程序的时间,每个线程被分配一个时间段,称作它的时间片。

在宏观上:俄们可以同时打开多个应用程序,每个程序并行不悖,同时运行。

但在微观上:由于只有一个CPU,一次只能处理程序要求的一部分,如何处理公平,一种方法就是引入时间片,每个程序轮流执行。

经典问题

使用PC寄存器存储字节码指令地址有什么用呢?

为什么使用PC寄存器记录当前线程的执行地址呢?

在本文的概述中已经讲到了Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的(也就是时间片分配),那么线程之间切换后如何保证再次回到该线程时继续执行接下来的指令呢?为了能够准确的记录各个线程正在执行的当前字节码的指令地址,最好的办法自然是为每一个线程都分配一个程序计数器。

说到这里其实又出现了一个问题,那就是程序执行的位置,这里我们只是取了指令,那么执行指令也需要一个线程私有的地方,不然也会出现和上述类似的问题。这个地方就是虚拟机栈,每一个线程都分配一个虚拟机栈,执行各自线程的任务。这样就解决了上述的问题。

以上是关于JVM学习笔记三:运行时数据区之程序计数器的主要内容,如果未能解决你的问题,请参考以下文章

JVM学习笔记六:运行时数据区之堆

JVM运行时数据区之虚拟机栈,本地方法栈和程序计数器

JVM运行时数据区之虚拟机栈,本地方法栈和程序计数器

JVM学习--JVM运行时数据区图文详解

JVM学习笔记运行时数据区

JVM学习笔记二:运行时数据区概述及JVM线程