JVM執行原理你是否已經get

JVM 運行時的數據區

.java 源代碼通過編譯成.class 字節碼文件,將字節碼文件運行在JVM中。接下來一起探討JVM運行時都有哪些數據區域。先上一張結構圖:

在這裏插入圖片描述

線程共享

線程共享:每個線程都能訪問這塊內存數據,隨着虛擬機或者GC而創建和銷燬。
由圖可知,線程共享分爲:方法區和堆內存。

方法區

方法區:用來存儲加載類信息,常量,靜態變量,編譯後的代碼等數據。
方法區存放着類的版本,字段,方法,接口和常量池。

堆內存

堆內存:JVM啓動時創建,存放對象的實例。垃圾回收器主要就是管理堆內存。如果滿了就會出現OOM。細分爲:老年代,新生代,(Eden,From Survivor,To Suvivor。

線程獨佔

線程獨佔:每個線程都會有它獨立的空間,隨生命週期而創建和銷燬。
由圖可知,線程獨佔分爲:虛擬機棧,本地方法棧,程序計數器。

虛擬機棧

虛擬機棧:爲虛擬機執行Java方法而準備的
每個線程都在這個空間有一個私有的空間,由多個棧幀組成(Stack Frame)組成
一個線程會執行一個或多個方法,一個方法對應一個棧幀。
棧幀內容包含:局部變量表,操作數棧,動態鏈接,方法返回地址,附加信息
棧內存默認最大1M,超出則拋出StackOverFlowError。

本地方法棧

本地方法棧:爲虛擬機執行Native 本地方法而準備的
虛擬機規範沒有規定具體的實現,由不同的虛擬機廠商去實現。
HotSpot虛擬機中虛擬機棧和本地方法棧的實現方式是一樣的,同樣超出大小以後也會拋出StackOverFlowError。

程序計數器(Program Counter Register)

程序計數器:用來記錄當前線程執行字節碼的位置,存儲的字節碼指令地址,如果執行Native方法,則計數器爲空。每個線程都在這個空間有一個私有空間,佔用內存空間很少。
CPU同一時間,只會執行一條線程中的指令,JVM多線程會輪流切換並分配CPU執行時間的方式,爲了線程切換後,需要通過程序計數器來恢復正確的執行位置。

案例一分析

代碼示例

public class Demo1 {
    public static void main(String[] args) {
        int x = 500;
        int y = 100;
        int z = x / y;
        System.out.println(z);
    }
}

在文件所在目錄執行編譯及其反編譯命令:

javac Demo1.java
javap -v Demo1.class

得到Demo1對應的指令碼:
在這裏插入圖片描述

運行過程分析

1)將主函數中的args放入本地變量表中,程序開始執行:
在這裏插入圖片描述
2)將500 壓入操作數棧,再同步到本地變量表中,程序計數器記錄代碼執行到第3行在這裏插入圖片描述
3)同樣的操作,代碼執行到第6行:在這裏插入圖片描述
4)將x/y的結果放到本地變量表中,代碼執行到第10行:
在這裏插入圖片描述
在這裏插入圖片描述
5) 執行完畢,返回結果

案例二分析

代碼示例

public class Demo2 {
    public static void main(String[] args) {
        int j = 0;
        for (int i = 0; i < 10; i++) {
            j = j++;
        }

        System.out.println(j);
    }
}

同樣執行編譯和反編譯查看指令碼:

javac Demo2.java
javap -v Demo2.class

運行過程分析

1) 初始化變量j在這裏插入圖片描述
2) 初始化for循環中的變量i:在這裏插入圖片描述
3) 執行for循環初始化:在這裏插入圖片描述
4)開始循環:

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

5)循環結束,返回結果爲0:

在程序計數器執行到11行的時候,對於JVM來說,先把j = 0 的值壓入到了操作數棧,,而在本地變量表中執行自增,但是操作數棧中還是原來的值。因此得到最後j的值始終是0;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章