JVM的理解

一、JVM內存結構

在這裏插入圖片描述

方法區和堆爲線程共享區,虛擬機棧、本地方法棧及程序計數器爲線程獨佔區。

二、棧內存結構

在這裏插入圖片描述

1.局部變量表

局部變量表(Local Variables Table)也可以稱之爲本地變量表,它包含在一個獨立的棧幀中。顧名思義,局部變量表主要用於存儲方法參數和定義在方法體內的局部變量,這些數據類型包括各類原始數據類型、對象引用(reference),以及returnAddress類型。局部變量表所需的容量大小在編譯期就可以被完全確定下來,並保存在方法的Code屬性中。大家思考一下,既然方法體內定義的局部變量是存儲在棧幀中的局部變量表裏的,那麼原始數據類型的成員變量的值是否也存儲在局部變量表中呢?其實如果是定義在方法體外的成員變量,不止是作用域發生了變化,更重要的是,其值也並非還是存儲在局部變量表裏,而是存儲在對象內存空間的實例數據中,整體來看即存儲在Java堆區內。簡單來說,與線程上下文相關的數據存儲在Java棧中,反之則存儲在Java堆區內。

2.操作數棧

每一個獨立的棧幀中除了包含局部變量表以外,還包含一個後進先出(Last-In-First-Out)的操作數棧,也可以稱之爲表達式棧(Expression Stack)。操作數棧和局部變量表在訪問方式上存在着較大差異,操作數棧並非採用訪問索引的方式來進行數據訪問的,而是通過標準的入棧和出棧操作來完成一次數據訪問。每一個操作數棧都會擁有一個明確的棧深度用於存儲數值,一個32bit的數值可以用一個單位的棧深度來存儲,而2個單位的棧深度則可以保存一個64bit的數值,當然操作數棧所需的容量大小在編譯期就可以被完全確定下來,並保存在方法的Code屬性中。

3.動態鏈接

每一個棧幀內部除了包含局部變量表和操作數棧之外,還包含一個指向運行時常量池中該棧幀所屬方法的引用,包含這個引用的目的就是爲了支持當前方法的代碼能夠實現動態鏈接(Dynamic Linking)。在運行時常量池,一個有效的字節碼文件中除了包含類的版本信息、字段、方法以及接口等描述信息外,還包含一項信息,那就是常量池表(Constant Pool Table),那麼運行時常量池就是字節碼文件中常量池表的運行時表示形式。在一個字節碼文件中,描述一個方法調用了另外的其他方法時,就是通過常量池中指向方法的符號引用(Symbolic Reference)來表示的,那麼動態鏈接的作用就是爲了將這些符號引用轉換爲調用方法的直接引用。

4.方法返回值

一個方法在執行的過程中將會產生兩種調用結果:一種是方法正常調用完成,而另外一種則是方法異常調用完成。如果是方法正常調用完成,那麼這就意味着,被調用的當前方法在執行的過程中將不會有任何的異常被拋出,並且方法在執行的過程中一旦遇見字節碼返回指令時,將會把方法的返回值返回給它的調用者,不過一個方法在正常調用完成之後究竟需要使用哪一個返回指令還需要根據方法返回值的實際數據類型而定。在字節碼指令中,返回指令包含ireturn(當返回值是boolean、byte、char、short和int類型時使用)、lreturn、freturn、dreturn以及areturn,另外還有一個return指令供聲明爲void的方法、實例初始化方法、類和接口的初始化方法使用。

三、運行常量池

默認不是new的時候會直接把我們的字符串對象放入我們的常量池之中,所有s1==s2返回是爲true

使用new的會後會在堆內存中創建對象所以的到的S3==S1返回的值爲false

在調用我們intern方法之後會把這個放入常量池中。這時候因爲常量池類似於hashSet則他們引入地址值就會一樣導致s3.intern() == s1返回true

public class Test2 {
    public static void main(String[] args) {
        String s1 ="abc";
        String s2 = "abc";
        System.out.println(s1 == s2);
        String s3 = new String("abc");
        System.out.println(s3 == s1);
        System.out.println(s3.intern() == s1);
    }
}

在這裏插入圖片描述

四、對象的創建類的過程

在這裏插入圖片描述

1.給對象分配內存

指針碰撞

我們內存分配爲規整的(每次分配依靠指針位移來分配對象)(但是我們電腦給java分配的內存不一定是規整的,可能區域並不是連續的) 如圖下所示:
在這裏插入圖片描述

空閒列表

堆內部有一個列表來存儲我們堆中空閒的地方。我們創建對象則去找列表中對應的空閒區域去創建我們的對象。
在這裏插入圖片描述
堆是否規整有我們垃圾回收器來決定的 ,如果垃圾回收帶有我們的 壓縮算法,那麼他會規整的分配我們的對象。

2.規整分配線程安全問題

指針碰撞有線程安全問題使用cas無鎖

空閒列表則採用我們的本地線程分配緩存,線程佔滿則採用我們的cas加鎖方式,再去分配本地緩存分配一部分區域。

3.初始化對象

4.執行構造方法

五、對象結構

發佈了104 篇原創文章 · 獲贊 35 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章