1. 程序計數器
JVM 種的程序計數器(Program Counter Register)中,Register 的命名源於 CPU 的寄存器,寄存器存儲指令相關的現場信息。CPU 只有把數據裝載到寄存器才能夠運行。
這里,並非是廣義上所指的物理寄存器,或許將其翻譯為 PC 計數器(或指令計數器)更加貼切(也稱為程序鈎子),並且也不容易引起誤會。
JVM 中 PC 寄存器是堆物理 PC 寄存器的一種抽象模擬。
作用
PC 寄存器用來存儲指向下一條指令的地址,即將要執行的指令代碼。由執行引擎讀取下一條指令。
特點
- 是一塊很小的內存空間,幾乎可以忽略不計。也是運行速度最快的存儲區域。
- 在 JVM 規范中,每個線程都有它自己的程序計數器,是線程私有的,生命周期與線程的生命周期保持一致。
- 任何時間一個線程都只有一個方法在執行,就是所謂的當前方法。程序計數器會存儲當前線程正在執行的Java方法的 JVM 指令地址。或者,如果執行的是 native 方法,則是未指定值(undefined)。
- 是程序控制流的指示器,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。
- 字節碼指示器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令。
- 是唯一一個在 Java 虛擬機規范中沒有規定任何 OutOfMemoryError 情況的區域。
2. 兩個問題
使用 PC 寄存器存儲字節碼指令有什么用?為什么使用 PC 寄存器記錄當前線程的執行地址呢?
因為 CPU 需要不斷切換各個線程,這時候切換回來后,就得知道接着從哪里開始繼續執行。
JVM 的字節碼計時器就需要通過改變 PC 寄存器的值來明確下一條應該執行什么樣的字節碼。
PC 寄存器為什么會被設定為線程私有?
所謂多線程在一個特定的時間段內只會指定其中某一個線程的方法,CPU 不停做任務切換,這樣必然導致經常中斷或恢復,如何保證分毫不差呢?為了能夠准確的記錄各個線程正在執行的當前字節碼指令地址,最好的辦法就是為每一個線程單獨分配一個 PC 寄存器,這樣一來各個線程之間便可以獨立計算,從而不會出現相互干擾的情況。
由於 CPU 時間片輪限制,眾多線程在並發執行的過程中,任何一個確定的時刻,一個處理器或者多核處理器中的 一個內核,只會執行某個線程中的一條指令。
這樣必然導致經常中斷或恢復,如何保證分毫不差呢?每個線程創建后,都會產生自己的程序計數器和棧幀,程序計數器在各個線程之間互不影響。