JVM03 - 程序计数器

川长思鸟来 2023-01-02 02:19 213阅读 0赞

目录

1.程序计数器概述

2.程序计数器作用

3.为什么使用程序计数器来记录当前线程的执行地址

4.程序计数器为什么被设定为线程私有


1.程序计数器概述

  1. 程序计数器(Program Counter Register):并非是广义上所指的物理寄存器,将其翻译为**PC计数器**(或**指令计数器**)会更加贴切(也称为**程序钩子**),**JVM中的PC寄存器是对物理PC寄存器的一种抽象模拟**。在JVM规范中,每个线程都有它自己的程序计数器,**是线程私有的**,生命周期与线程的生命周期保持一致。程序计数器会存储当前线程正在执行的Java方法的JVM指令地址(如果是在执行native方法,则是undefned)。它是**程序控制流**的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖此计数器来完成。字节码解释器工作时就是通过改变程序计数器的值来选取下一条需要执行的字节码指令。它是唯一一个在Java虚拟机规范中没有规定任何OutofMemoryError情况的区域。

2.程序计数器作用

  1. 程序计数器作用:**存储指向下一条指令的地址,由执行引擎将指令解释为机器码后交由cpu进行处理。**

Demo:

  1. public class PCRegisterTest {
  2. public static void main(String[] args) {
  3. int i = 10;
  4. int j = 20;
  5. int k = i + j;
  6. String s = "abc";
  7. System.out.println(i);
  8. System.out.println(k);
  9. }
  10. }

反编译:javap -v xxx.class

  1. Constant pool:
  2. #1 = Methodref #6.#26 // java/lang/Object."<init>":()V
  3. #2 = String #27 // abc
  4. #3 = Fieldref #28.#29 // java/lang/System.out:Ljava/io/PrintStream;
  5. #4 = Methodref #30.#31 // java/io/PrintStream.println:(I)V
  6. #5 = Class #32 // com/atguigu/java/PCRegisterTest
  7. #6 = Class #33 // java/lang/Object
  8. #7 = Utf8 <init>
  9. #8 = Utf8 ()V
  10. #9 = Utf8 Code
  11. #10 = Utf8 LineNumberTable
  12. #11 = Utf8 LocalVariableTable
  13. #12 = Utf8 this
  14. #13 = Utf8 Lcom/atguigu/java/PCRegisterTest;
  15. #14 = Utf8 main
  16. #15 = Utf8 ([Ljava/lang/String;)V
  17. #16 = Utf8 args
  18. #17 = Utf8 [Ljava/lang/String;
  19. #18 = Utf8 i
  20. #19 = Utf8 I
  21. #20 = Utf8 j
  22. #21 = Utf8 k
  23. #22 = Utf8 s
  24. #23 = Utf8 Ljava/lang/String;
  25. #24 = Utf8 SourceFile
  26. #25 = Utf8 PCRegisterTest.java
  27. #26 = NameAndType #7:#8 // "<init>":()V
  28. #27 = Utf8 abc
  29. #28 = Class #34 // java/lang/System
  30. #29 = NameAndType #35:#36 // out:Ljava/io/PrintStream;
  31. #30 = Class #37 // java/io/PrintStream
  32. #31 = NameAndType #38:#39 // println:(I)V
  33. #32 = Utf8 com/atguigu/java/PCRegisterTest
  34. #33 = Utf8 java/lang/Object
  35. #34 = Utf8 java/lang/System
  36. #35 = Utf8 out
  37. #36 = Utf8 Ljava/io/PrintStream;
  38. #37 = Utf8 java/io/PrintStream
  39. #38 = Utf8 println
  40. #39 = Utf8 (I)V
  41. {
  42. public com.atguigu.java.PCRegisterTest();
  43. descriptor: ()V
  44. flags: ACC_PUBLIC
  45. Code:
  46. stack=1, locals=1, args_size=1
  47. 0: aload_0
  48. 1: invokespecial #1 // Method java/lang/Object."<init>":()V
  49. 4: return
  50. LineNumberTable:
  51. line 7: 0
  52. LocalVariableTable:
  53. Start Length Slot Name Signature
  54. 0 5 0 this Lcom/atguigu/java/PCRegisterTest;
  55. public static void main(java.lang.String[]);
  56. descriptor: ([Ljava/lang/String;)V
  57. flags: ACC_PUBLIC, ACC_STATIC
  58. Code:
  59. stack=2, locals=5, args_size=1
  60. 0: bipush 10
  61. 2: istore_1
  62. 3: bipush 20
  63. 5: istore_2
  64. 6: iload_1
  65. 7: iload_2
  66. 8: iadd
  67. 9: istore_3
  68. 10: ldc #2 // String abc
  69. 12: astore 4
  70. 14: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
  71. 17: iload_1
  72. 18: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
  73. 21: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
  74. 24: iload_3
  75. 25: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
  76. 28: return
  77. LineNumberTable:
  78. line 10: 0
  79. line 11: 3
  80. line 12: 6
  81. line 14: 10
  82. line 15: 14
  83. line 16: 21
  84. line 18: 28
  85. LocalVariableTable:
  86. Start Length Slot Name Signature
  87. 0 29 0 args [Ljava/lang/String;
  88. 3 26 1 i I
  89. 6 23 2 j I
  90. 10 19 3 k I
  91. 14 15 4 s Ljava/lang/String;

左边的数字代表指令地址(指令偏移),即程序计数器中存储的值,由执行引擎将指令解释为机器码后交由cpu进行处理。

image-20200727212024900

3.为什么使用程序计数器来记录当前线程的执行地址

因为线程是一个个的顺序执行流,CPU需要不停的切换各个线程,从线程A切换回来的线程B需要知道从哪行代码开始继续执行(JVM的字节码解释器需要通过改变程序计数器的值来明确下一条应该执行什么样的字节码指令)。

4.程序计数器为什么被设定为线程私有

  1. 由于CPU时间片轮转的限制,众多线程在并发执行过程中,任何一个确定的时刻,一个处理器或者多核处理器中的一个内核,只会执行某个线程中的一条指令。这样必然导致线程经常中断或恢复,如何保证分毫无差呢? 为了能够准确地记录各个线程正在执行的当前字节码指令地址,最好的办法自然是为每一个线程都分配一个程序计数器,这样一来各个线程之间便可以进行独立计算,从而不会出现相互干扰的情况。

发表评论

表情:
评论列表 (有 0 条评论,213人围观)

还没有评论,来说两句吧...

相关阅读

    相关 jvm程序计数器

    在Java虚拟机(JVM)中,程序计数器(PC寄存器)是一块较小的内存空间,它用于存储当前线程正在执行的Java字节码的指令地址。程序计数器是线程私有的,每个线程都有自己...

    相关 JVM_程序计数器详解

    1、内存管理 2 、运行时数据区域内容 > Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。根据《Java虚拟机规范》的规定,

    相关 4、jvm程序计数器

    一. 介绍 程序计数器是一块较小的内存空间,它的作用可以看作是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里字节码解释器工作时就是通过改变这个计数器的值来选取下