憨人筆記之JVM-運行時數據區(程序計數器)

話很少說,幹就完了。java

先上圖,在以前的文章中,詳細介紹了類加載子系統。這裏先回顧一下。類加載子系統中的核心部分

  • 類加載過程(類的生命週期)包括加載、鏈接(驗證、準備、解析)、初始化、使用、卸載這麼幾個過程
  • 系統類加載器,引導類加載器、拓展類加載器、應用類加載器的原理
  • 雙親委派機制的工做原理及實際意義

針對上面的提綱,回想一下是否可以記得每一個類別每一個小點的細節。多線程

本章內容將着重講述類加載子系統完成類加載以後JVM運行時數據區域。spa

運行時數據區

運行時數據區是虛擬機在執行Java程序的過程成中把所管理的內存劃分紅不一樣的數據區域。每一個區域各司其職,有本身的生命週期,保證程序的穩定運行。有些區域隨着虛擬機進程的啓動而存在,而有些區域則依賴用戶線程的啓動和結束而創建和銷燬。線程

如上圖所示,運行時候數據區主要劃分紅5大塊:程序計數器(Program Counter Register)、虛擬機棧(Java Virtual Machine Stack)、本地方法棧(Native Method Stack)、方法區(Method)、堆(Heap)。按照線程共享的角度上來看,又分爲線程共享數據區線程隔離數據區翻譯

接下來,詳細說說各區域在虛擬機中承擔着什麼樣的角色和做用。設計

程序計數器

程序計數器也被叫作PC寄存器。它是存儲指令相關的現場信息,CPU只有把數據裝在寄存器中,程序纔可以正常執行。程序計數器是一塊很小的內存區域,同其餘數據區域相比,也是運行速度最快的存儲區域3d

它的主要做用就是存儲指向下一條指令的地址,也就是將要執行的指令代碼,執行引擎會獲取它的下一條指令。它就是當前線程所執行的字節碼的行號標示。翻譯成咱們容易理解的話來說,能夠想象成咱們在IDEA中編寫代碼時候的行號。而執行引擎經過這個行號,能定位到當前行的代碼是什麼,它將作什麼事情。下面用一個僞代碼來進行解釋:code

1	public class ProgramCounterRegisterTest {
2    		public static void main(String[] args){
3        		int i = 1;
4        		System.out.println("打印變量i的值:" + i);
5    		}
6	}
// 例如行號爲3, 它將進行爲變量i賦值爲1的操做。這裏行號3就能夠看做成PC寄存器中指令的地址,int i = 1 能夠看做要執行的指令
複製代碼

經過javap對這個類的class字節碼文件進行反編譯,來看看在字節碼文件中,什麼表示指令地址:cdn

當執行引擎在執行指令的時候,就會從PC寄存器中經過指令地址"0"找到其對應的指令爲iconst_1而後再進行指令的執行(後面對字節碼文件會有詳細的介紹)。blog

程序計數器做爲運行時數據區的重要組成部分,具備一下特色:

  • 線程私有,每個線程都會有本身獨立的程序計數器,各線程之間互不干擾,生命週期伴同線程的生命週期一致
  • 若是執行的是Java方法,會保存虛擬機正在執行的字節碼文件的指令地址,若是執行的是Native方法,計數器的值爲空(undifined)
  • 程序的控制流指示器,分支、循環、跳轉、異常處理、線程恢復等功能都依賴它來完成
  • 是整個虛擬機運行時數據區惟一不會發生OutOfMemoryError的內存區域。
程序計數器存儲的字節碼指令地址有何做用?爲何要記錄當前線程的執行地址?

現入現在的程序都會存在多線程的狀況,可是CPU一次只能執行一個線程,CPU經過時間片來控制線程的切換,時間片的時間很小,使得感受是在多個線程在同時執行。因此,如何保證程序在多線程在線程切換的過程當中,可以還原到線程上次執行的代碼呢,就是經過程序計數器。

因爲程序計數器是線程私有的,對於一個線程來講,字節碼解釋器會經過改變程序計數器中的指令地址來明確下一條應該執行什麼指令,而在多線程的狀況下,在線程切換的時候,可以保證切換回來的線程可以在以前的基礎上繼續執行,從而保證程序的正常運行。以上,就是程序計數器是必不可少的也是要設計成線程私有的緣由。

程序計數器相對來講在整個運行時數據區屬於比較簡單的數據區域。主要就是如上圖的幾點內容。


不怕路歹行不怕大雨淋,心上一字敢 面對個人夢,甘願來做憨人。 --<憨人>

相關文章
相關標籤/搜索