JVM中的程序計(jì)數(shù)寄存器PC是什么詳解
一、PC寄存器概述
CPU只有把數(shù)據(jù)裝載到寄存器才能夠運(yùn)行。這里,并非是廣義上所指的物理寄存器,或許將其翻譯為PC計(jì)數(shù)器(或指令計(jì)數(shù)器)會(huì)更加貼切(也稱為程序鉤子),并且也不容易引起一些不必要的誤會(huì)。JVM中的PC寄存器是對物理PC寄存器的一種抽象模擬。
簡單介紹
1、 PC寄存器是一塊很小的內(nèi)存空間,幾乎可以忽略不計(jì),也是運(yùn)行速度最快的存儲(chǔ)區(qū)域。
2、 在JVM規(guī)范中,每個(gè)線程都有它自己的PC寄存器,是線程私有的,生命周期與線程的生命周期保持一致。
3、 任何時(shí)間一個(gè)線程都只有一個(gè)方法在執(zhí)行,也就是所謂的當(dāng)前方法,PC寄存器會(huì)存儲(chǔ)當(dāng)前線程的正在執(zhí)行的Java方法的JVM指令地址;或者,如果是執(zhí)行的native方法,則是未指定值。
4、 PC寄存器是程序控制流的指示器,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個(gè)寄存器來完成。
5、 字節(jié)碼解釋器工作時(shí)就是通過改變這個(gè)寄存器的值來選取下一條需要執(zhí)行的字節(jié)碼指令。
6、 PC寄存器是唯一 一個(gè)在Java虛擬機(jī)規(guī)范中沒有規(guī)定任何OutOfMemoryError情況的區(qū)域。
注:方法區(qū)(元數(shù)據(jù)區(qū))和堆區(qū)是有GC(垃圾回收)的,而棧區(qū)和PC寄存器是沒有的;棧區(qū)、方法區(qū)、堆區(qū)是有OOM(OutOfMemoryError)的,而PC寄存器沒有。
二、PC寄存器的作用
PC寄存器用來存儲(chǔ)指向下一條指令的地址,即將要執(zhí)行的指令代碼。由執(zhí)行引擎讀取下一條指令。
每一個(gè)棧幀就相當(dāng)于存儲(chǔ)了一個(gè)方法,棧幀中的每一個(gè)指令都有一個(gè)標(biāo)識(shí),這里PC寄存器就存儲(chǔ)了指令的地址,起標(biāo)識(shí)作用,然后執(zhí)行引擎就根據(jù)這個(gè)標(biāo)識(shí)來讀取到下一條指令。
三、PC寄存器舉例說明
public class PcRegisterTest { public static void main(String[] args) { int i = 10; int j = 5; int k = i+j; } }
這里我們運(yùn)行編譯下這段代碼,然后在進(jìn)入到out對應(yīng)的目錄下執(zhí)行javap命令:
我們就可以看到反編譯的一個(gè)結(jié)果:
上圖紅色框里的數(shù)字就是指令地址或者偏移地址,其就是PC寄存器里面存儲(chǔ)的地址。藍(lán)色框里的就是操作指令。然后執(zhí)行引擎就根據(jù)這個(gè)指令地址取出指定的操作指令來操作虛擬機(jī)棧(局部變量表、操作數(shù)表),并且翻譯成機(jī)器指令,讓CPU對相應(yīng)的計(jì)算。
四、解決PC寄存器常問到的兩個(gè)面試問題
1、使用PC寄存器存儲(chǔ)字節(jié)碼指令地址有什么用呢?
(為什么使用PC寄存器記錄當(dāng)前線程的執(zhí)行地址呢?)
因?yàn)镃PU需要不停的切換各個(gè)線程,這時(shí)候切換回來后,就得知道是從哪個(gè)指令開始繼續(xù)執(zhí)行。JVM的字節(jié)碼解釋器就需要通過改變PC寄存器的值來明確下一條應(yīng)該執(zhí)行什么樣的字節(jié)碼按指令。
2、PC寄存器為什么會(huì)被設(shè)定為線程私有的,一個(gè)線程一份?
我們都知道所謂的多線程在一個(gè)特定的時(shí)間段內(nèi)只會(huì)執(zhí)行其中某一個(gè)線程的方法,CPU會(huì)不停地做任務(wù)切換,這樣必然導(dǎo)致經(jīng)常中斷或恢復(fù),如何保證分毫無差呢?
1.為了能夠準(zhǔn)確地記錄各個(gè)線程正在執(zhí)行的當(dāng)前字節(jié)碼指令地址,最好的辦法自然是為每一個(gè)線程都分配一個(gè)PC寄存器,這樣一來各個(gè)線程之間便可以進(jìn)行獨(dú)立計(jì)算,從而不會(huì)出現(xiàn)相互干擾的情況。
2.由于CPU時(shí)間片輪限制,眾多線程在并發(fā)執(zhí)行過程中,任何一個(gè)確定的時(shí)刻,一個(gè)處理器或者多核處理器中的一個(gè)內(nèi)核,只會(huì)執(zhí)行某個(gè)線程中的一條指令。
3.這樣必然導(dǎo)致經(jīng)常中斷或恢復(fù),如何保證分毫無差呢?每個(gè)線程在創(chuàng)建后,都會(huì)產(chǎn)生自己的程序計(jì)數(shù)器和棧幀,程序計(jì)數(shù)器在各個(gè)線程之間互不影響。
五、CPU時(shí)間片
CPU時(shí)間片: 即CPU分配給各個(gè)程序的時(shí)間,每個(gè)線程被分配一個(gè)時(shí)間段,稱作它的時(shí)間片。
在宏觀上: 我們可以同時(shí)打開多個(gè)應(yīng)用程序,每個(gè)程序并行不悖,同時(shí)運(yùn)行。
但在微觀上: 由于只有一個(gè)CPU,一次只能處理程序要求的一部分,如何處理公平,一種方法就是引入時(shí)間片,每個(gè)程序輪流執(zhí)行。
總的來說,我們用一句話來概括:宏觀并行,微觀并發(fā)。
簡單圖示:
PC寄存器就到這里以上就是JVM中的程序計(jì)數(shù)寄存器PC原理分析的詳細(xì)內(nèi)容,更多關(guān)于JVM程序計(jì)數(shù)寄存器PC原理的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java Bean與json對象間的轉(zhuǎn)換實(shí)例講解
在本篇文章里小編給大家整理的是關(guān)于java Bean與json間的轉(zhuǎn)換的實(shí)例內(nèi)容,有需要的朋友們吧可以學(xué)習(xí)參考下。2020-01-01解決swagger主頁訪問,返回報(bào)錯(cuò)500問題
在使用Swagger時(shí)遇到500錯(cuò)誤,通過仔細(xì)的debug發(fā)現(xiàn)問題源于注解使用不當(dāng),具體表現(xiàn)為一個(gè)接口的入?yún)⒈诲e(cuò)誤地注解了三個(gè)參數(shù),而實(shí)際上只有兩個(gè),這導(dǎo)致了Swagger在解析時(shí)拋出了NullPointerException異常,解決方法是刪除錯(cuò)誤的第三個(gè)參數(shù)的注解2024-09-09Spring AOP攔截-三種方式實(shí)現(xiàn)自動(dòng)代理詳解
這篇文章主要介紹了Spring AOP攔截-三種方式實(shí)現(xiàn)自動(dòng)代理詳解,還是比較不錯(cuò)的,這里分享給大家,供需要的朋友參考。2017-11-11Java實(shí)現(xiàn)導(dǎo)出合并Excel單元格
隨著數(shù)據(jù)的不斷增長,很多時(shí)候需要將數(shù)據(jù)導(dǎo)出到Excel中進(jìn)行分析、處理和展示。本文將介紹如何使用Java實(shí)現(xiàn)Excel導(dǎo)出,并且可以合并單元格,需要的可以參考一下2023-04-04idea中Java實(shí)體類怎樣生成序列化的版本號(hào)的方法
這篇文章主要介紹了idea中Java實(shí)體類怎樣生成序列化的版本號(hào)的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11