一、結構圖
1、程序計數器Program Counter Register
(1)是當前線程所執行的字節碼的行號指示器
(2)由於java虛擬機的多線程是通過線程輪流切換並分配處理器執行時間的方式來實現的,在任何一個確定的時刻,一個處理器都只會執行一條線程中的指令。爲了線程切換後能恢復到正確的執行位置,每個線程都需要一個線程私有的計數器,互不影響
(3)如果線程正在執行的是一個java方法,計數器記錄的是正在執行的虛擬機字節碼指令的地址如果正在執行的是一個native方法,計數器值爲空
(4)是唯一一個在java虛擬機規範中沒有規定任何OutOfMemoryError情況的區域
二、Java虛擬機棧
虛擬機棧的棧元素是棧幀,當有一個方法被調用時,代表這個方法的棧幀入棧;當這個方法返回時,代表哦這個方法的棧幀出棧。
棧幀,一部分是局部變量表,存放了編譯器可知的各種基本數據類型、對象引用、returnAddress類型另一部分是操作數棧,用來存放操作數
JVM字節碼指令執行1+2的過程
iconst_1 //把整數 1 壓入操作數棧
iconst_2 //把整數 2 壓入操作數棧
iadd //棧頂的兩個數相加後出棧,結果入棧
注意,局部變量表中的變量不可直接使用,如需使用必須通過相關指令將其加載至操作數棧作爲操作數使用
比如有一個方法foo(),其中的代碼爲:int a = 1+2;int b = a + 3;
編譯爲字節碼就是:
iconst_1 //把整數 1 壓入操作數棧
iconst_2 //把整數 2 壓入操作數棧
iadd //棧頂的兩個數出棧後相加,結果入棧;實際上前三步會被編譯器優化爲:iconst_3
istore_1 //把棧頂的內容放入局部變量表中索引爲 1 的 slot 中,也就是 a 對應的空間中
iload_1 // 把局部變量表索引爲 1 的 slot 中存放的變量值
加載至操作數棧iconst_3
iadd //棧頂的兩個數出棧後相加,結果入棧
istore_2 // 把棧頂的內容放入局部變量表中索引爲 2 的 slot 中,也就是 b 對應的空間中
return // 方法返回指令,回到調用點
這張圖是虛擬機的結構
目前只有long和double類型的數據會佔用2個局部變量空間(slot)
在Java虛擬機規範中,對這個區域規定了兩種異常情況:
如果線程請求的棧深度大於虛擬機所允許的深度,將拋出StackOverflowError異常
如果虛擬機棧可以動態擴展,如果擴展時,無法申請到足夠的內存,就會拋出OutOfMemoryError異常
三、本地方法棧
和虛擬機棧發揮的作用是非常相似的,它們之間的區別不過是虛擬機棧爲虛擬機執行java方法(也就是字節碼)服務,而本地方法棧則爲虛擬機使用到的Native方法服務。
同樣也會拋出StackOverflowError和OutOfMemoryError異常
四、方法區
線程之間共享內存會拋出OOM異常存儲每個類的結構信息,如運行時常量池、字段、方法數據、構造函數、普通方法的字節碼內容