內存結構篇:程序計數器


參考:https://www.cnblogs.com/newAndHui/p/11878504.html

一、定義

Program Counter Register 程序計數器(寄存器)(線程獨享):程序計數器是一塊 較小 的內存空間,它可以看做是當前線程所執行的字節碼的 行號指示器 ;在虛擬機的概念模型里(僅僅是概念模型,各種虛擬機可能會通過一些更高效的方式去實現),字節碼解釋器工作時,就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳准、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成 ;

  • 作用:記錄正在執行的虛擬機字節碼指令的地址(如果正在執行的是本地方法則為空
  • 特點:
    • 是線程私有的
    • 不會存在內存溢出
    • 生命周期隨着線程,線程啟動而產生,線程結束而消亡

二、特點詳解

理解:程序計數器,可以看做是當前線程執行的字節碼的 行號指示器

//當java 文件被翻譯為字節碼的時候,字節碼大概類似於下面的樣子
public void test() {
    0 xxxx ..
    2 xxxx ..
    4 xxxx ..
    5 xxxx ..
}

上面左邊的0、2、4、5,就是類似於字節碼的行號(實際是指令的偏移地址),程序計數器中保存的值就是它們;字節碼解釋器,就是根據它們來執行程序的。

三、深入了解

java是支持多線程的,當CPU執行權從 A 線程,轉移到 B 線程的時候,JVM就要暫時掛起線程 A ,去執行線程 B ;當線程 A 再次得到CPU執行權的時候,又會掛起B線程,繼續執行 A 線程 ;

1、CPU是怎么記住之前的A線程,執行到哪一處的:

CPU根本就不會記住之前執行到哪里了,它只是埋頭苦干;

2、那是什么保證了切換線程的程序可以正常執行的:

程序計數器 ;程序計數器里面保存的是 當前線程執行的字節碼的行號(看着像行號,其實是指令地址);

3、那么,我們需要幾個程序計數器呢:每個線程都需要有一個獨立的程序計數器

如果只有一個的話,切換B線程以后,程序計數器里面保存的就是B線程所執行的字節碼的行號了,再切換回A線程,就蒙圈了,不知道執行到哪里了,因為,程序計數器里面保存的是B線程當前執行的字節碼地址 ;因此,我們可以想象出,要為每個線程都分配一個程序計數器因此,程序計數器的內存空間是線程私有的 ;這樣即使線程 A 被掛起,但是線程 A 里面的程序計數器,記住了A線程當前執行到的字節碼的指令地址了 ,等再次切回到A線程的時候,看一下程序計數器,就知道之前執行到哪里了

4、那么程序計數器,什么時候分配內存呢:

一個線程在執行的任何期間,都會失去CPU執行權,因此,我們要從一個線程被創建開始執行,就要無時無刻的記錄着該線程當前執行到哪里了!因此,線程計數器,必須是線程被創建開始執行的時候,就要一同被創建

5、程序計數器為什么不會存在內存溢出:

程序技術器保存的是當前執行的字節碼的偏移地址,當執行到下一條指令的時候,改變的只是程序計數器中保存的地址,並不需要申請新的內存來保存新的指令地址,因此,永遠都不可能內存溢出;因此,jvm虛擬機規范,也就沒有規定,也是唯一一個沒有規定 OutOfMemoryError 異常 的區域(即在同一塊內存上更改字節碼的偏移地址,不需要再創建新的內存來保存

6、為什么當線程執行的是本地方法的時候,程序計數器中保存的值是空:

因為本地方法是 C++/C 寫的,由系統調用,根本不會產生字節碼文件,因此,程序計數器也就不會做任何記錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM