JVM(四)程序計(jì)數(shù)器

上篇(JVM內(nèi)存與垃圾回收篇)大綱

  1. JVM與Java體系結(jié)構(gòu)
  2. 類加載子系統(tǒng)
  3. 運(yùn)行時(shí)數(shù)據(jù)區(qū)概述及線程
  4. 程序計(jì)數(shù)器(PC寄存器)
  5. 虛擬機(jī)棧
  6. 本地方法接口
  7. 本地方法棧
  8. 方法區(qū)
  9. 直接內(nèi)存
  10. 執(zhí)行引擎
  11. StringTable
  12. 垃圾回收概述
  13. 垃圾回收算法
  14. 垃圾回收概念
  15. 垃圾回收器

程序計(jì)數(shù)器(PC寄存器)

目錄

  1. PC Register介紹
  2. 舉例說明
  3. 兩個(gè)常見問題

1. PC Register介紹

虛擬機(jī)規(guī)范官方地址:https://docs.oracle.com/javase/specs/jvms/se8/html/
官方規(guī)范的第5.2.1節(jié)就是關(guān)于PC Register的介紹。

1.png

JVM中的程序計(jì)數(shù)寄存器(Program Counter Register)中,Register的命名源于CPU的寄存器,寄存器存儲(chǔ)指令相關(guān)的現(xiàn)場(chǎng)信息。CPU只有把數(shù)據(jù)裝載到寄存器才能夠運(yùn)行。
這里,并非是廣義上所指的物理寄存器,或許將其翻譯為PC計(jì)數(shù)器(或指令計(jì)數(shù)器)會(huì)更加貼切(也稱為程序鉤子),并且也不容易引起一些不必要的誤會(huì)。JVM中的PC寄存器是對(duì)物理PC寄存器的一種抽象模擬。


2.png

作用:PC寄存器用來存儲(chǔ)指向下一條指令的地址,也即是將要執(zhí)行的指令代碼。由執(zhí)行引擎讀取下一條指令。

  • 它是一塊很小的內(nèi)存空間,幾乎可以忽略不記。也是運(yùn)行速度最快的存儲(chǔ)區(qū)域。
  • 在JVM規(guī)范中,每個(gè)線程都有它自己的程序計(jì)數(shù)器,是線程私有的,生命周期與線程的生命周期保持一致。
  • 任何時(shí)間一個(gè)線程都只有一個(gè)方法在執(zhí)行,也就是所謂的當(dāng)前方法。程序計(jì)數(shù)器會(huì)存儲(chǔ)當(dāng)前線程正在執(zhí)行的Java方法的JVM指令地址;或者,如果是在執(zhí)行native方法,則是未指定值(undefined)。
  • 它是程序控制流的指示器,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個(gè)計(jì)數(shù)器來完成。
  • 字節(jié)碼解釋器工作時(shí)就是通過改變這個(gè)計(jì)數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令。
  • 它是唯一一個(gè)在Java虛擬機(jī)規(guī)范中沒有規(guī)定任何outotMemoryError情況的區(qū)域。

2. 舉例說明(PC寄存器的使用舉例)

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);
    }
}

找到輸出目錄下的字節(jié)碼文件,執(zhí)行javap - verbose PC命令,查看反編譯的結(jié)果,部分如下:左側(cè)數(shù)字是指令地址(或叫偏移地址),右側(cè)是操作指令

stack=2, locals=5, args_size=1
0: bipush          10
2: istore_1
3: bipush          20
5: istore_2
6: iload_1
7: iload_2
8: iadd
9: istore_3
10: ldc             #2      //String abc
12: astore          4    
14: getstatic       #3      //Field java/lang/System.out:Ljava/io/PrintStream;
3.png

執(zhí)行引擎去PC寄存器指向的下一個(gè)指令地址位置(比如圖3中5)取操作指令(圖中istore_2),其中涉及操作局部變量表、操作數(shù)棧,把字節(jié)碼指令翻譯成機(jī)器指令,讓CPU做運(yùn)算。

3. 兩個(gè)常見問題

3.1 第一個(gè)問題

  • 使用PC寄存器存儲(chǔ)字節(jié)碼指令地址有什么用呢?
  • 為什么使用PC寄存器記錄當(dāng)前線程的執(zhí)行地址呢?


    4.png

因?yàn)镃PU需要不停的切換各個(gè)線程,這時(shí)候切換回來以后,就得知道接著從哪開始繼續(xù)執(zhí)行。
JVM的字節(jié)碼解釋器就需要通過改變PC寄存器的值來明確下一條應(yīng)該執(zhí)行什么樣的字節(jié)碼指令。

3.2 第二個(gè)問題

  • PC寄存器為什么會(huì)被設(shè)定為線程私有?

我們都知道所謂的多線程在一個(gè)特定的時(shí)間段內(nèi)只會(huì)執(zhí)行其中某一個(gè)線程的方法,CPU會(huì)不停地做任務(wù)切換,這樣必然導(dǎo)致經(jīng)常中斷或恢復(fù),如何保證分毫無差呢?為了能夠準(zhǔn)確地記錄各個(gè)線程正在執(zhí)行的當(dāng)前字節(jié)碼指令地址,最好的辦法自然是為每一個(gè)線程都分配一個(gè)PC寄存器,這樣一來各個(gè)線程之間便可以進(jìn)行獨(dú)立計(jì)算,從而不會(huì)出現(xiàn)相互干擾的情況。

由于CPU時(shí)間片輪限制,眾多線程在并發(fā)執(zhí)行過程中,任何一個(gè)確定的時(shí)刻,一個(gè)處理器或者多核處理器中的一個(gè)內(nèi)核,只會(huì)執(zhí)行某個(gè)線程中的一條指令。

這樣必然導(dǎo)致經(jīng)常中斷或恢復(fù),如何保證分毫無差呢?每個(gè)線程在創(chuàng)建后,都會(huì)產(chǎn)生自己的程序計(jì)數(shù)器和棧幀,程序計(jì)數(shù)器在各個(gè)線程之間互不影響。

時(shí)間片
CPU時(shí)間片即CPU分配給各個(gè)程序的時(shí)間,每個(gè)線程被分配一個(gè)時(shí)間段,稱作它的時(shí)間片。
在宏觀上:我們可以同時(shí)打開多個(gè)應(yīng)用程序,每個(gè)應(yīng)用程序并行不悖,同時(shí)運(yùn)行。
但在微觀上:由于只有一個(gè)CPU,一次只能處理程序要求的一部分,如何處理公平,一種方法就是引入時(shí)間片,每個(gè)程序輪流執(zhí)行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容