【JVM以內存與垃圾回收篇】程序計數器

程序計數器

介紹


JVM 中的程序計數寄存器(Program Counter Register)中,Register 的命名源於 CPU 的寄存器,寄存器存儲指令相關的現場信息。CPU 只有把數據裝載到寄存器纔可以運行。java

這裏,並不是是廣義上所指的物理寄存器,或許將其翻譯爲 PC 計數器(或指令計數器)會更加貼切(也稱爲程序鉤子),而且也不容易引發一些沒必要要的誤會。JVM 中的 PC 寄存器是對物理 PC 寄存器的一種抽象模擬。bash

它是一塊很小的內存空間,幾乎能夠忽略不記。也是運行速度最快的存儲區域。多線程

在 JVM 規範中,每一個線程都有它本身的程序計數器,是線程私有的,生命週期與線程的生命週期保持一致。併發

任什麼時候間一個線程都只有一個方法在執行,也就是所謂的當前方法。程序計數器會存儲當前線程正在執行的 Java 方法的 JVM 指令地址;或者,若是是在執行 native 方法,則是未指定值(undefned)。線程

它是程序控制流的指示器,分支、循環、跳轉、異常處理、線程恢復等基礎功能都須要依賴這個計數器來完成。字節碼解釋器工做時就是經過改變這個計數器的值來選取下一條須要執行的字節碼指令。翻譯

它是惟一一個在 Java 虛擬機規範中沒有規定任何 OutOfMemoryError 狀況的區域。code

做用


做用:PC 寄存器用來存儲指向下一條指令的地址,也即將要執行的指令代碼。由執行引擎讀取下一條指令。blog

代碼演示

咱們首先寫一個簡單的代碼生命週期

/**程序計數器
 * @author: Nemo
 */
public class PCRegisterTest {
    public static void main(String[] args) {
        int i = 10;
        int j = 20;
        int k = i + j;
    }
}

而後將代碼進行編譯成字節碼文件,咱們再次查看,發如今字節碼的左邊有一個行號標識,它其實就是指令地址,用於指向當前執行到哪裏。ip

0: bipush        10
2: istore_1
3: bipush        20
5: istore_2
6: iload_1
7: iload_2
8: iadd
9: istore_3
10: return

經過 PC 寄存器,咱們就能夠知道當前程序執行到哪一步了!

使用 PC 寄存器存儲字節碼指令地址有什麼用呢?

由於 CPU 須要不停的切換各個線程,這時候切換回來之後,就得知道接着從哪開始繼續執行。

JVM 的字節碼解釋器就須要經過改變 PC 寄存器的值來明確下一條應該執行什麼樣的字節碼指令。

PC 寄存器爲何被設定爲私有的?

咱們都知道所謂的多線程在一個特定的時間段內只會執行其中某一個線程的方法,CPU 會不停地作任務切換,這樣必然致使常常中斷或恢復,如何保證分毫無差呢?爲了可以準確地記錄各個線程正在執行的當前字節碼指令地址,最好的辦法天然是爲每個線程都分配一個 PC 寄存器,這樣一來各個線程之間即可以進行獨立計算,從而不會出現相互干擾的狀況。

因爲 CPU 時間片輪限制,衆多線程在併發執行過程當中,任何一個肯定的時刻,一個處理器或者多核處理器中的一個內核,只會執行某個線程中的一條指令。

這樣必然致使常常中斷或恢復,如何保證分毫無差呢?每一個線程在建立後,都會產生本身的程序計數器和棧幀,程序計數器在各個線程之間互不影響。

CPU 時間片

CPU 時間片即 CPU 分配給各個程序的時間,每一個線程被分配一個時間段,稱做它的時間片。

在宏觀上:咱們能夠同時打開多個應用程序,每一個程序並行不悖,同時運行。

但在微觀上:因爲只有一個 CPU,一次只能處理程序要求的一部分,如何處理公平,一種方法就是引入時間片,每一個程序輪流執行。

相關文章
相關標籤/搜索