Java 類加載過程梳理,一篇搞定

最近在看 Java 虛擬機,正好看到類加載這塊,所以簡單記錄下所學到的知識,作爲筆記。

首先,我們編寫好的 Java 代碼,經過編譯變成.class文件,然後類加載器把.class字節碼文件加載到 JVM 中,接着執行我們的代碼,最後將類卸載出 JVM。而從類加載到虛擬機到卸載出虛擬機的這一整個生命週期總共可以分爲 7 個步驟,分別爲加載、驗證、準備、解析、初始化、使用和卸載,其中驗證、準備和解析又稱爲連接階段。接下來簡單介紹下各個階段是幹嘛的。

加載是 “類加載” 的第一個階段,就是將需要用到的類對應的. class 字節碼文件加載到虛擬機內存,並在方法區中生成一個java.lang.Class對象,作爲程序訪問這個類的各種數據的訪問入口。

public class Test {
    public static void main(String[] args) {
        User user = new User();
    }
}

看一下上面這段代碼,經過編譯會生成兩個字節碼文件Test.classUser.class,接着會將包含 main 方法的這個類加載到虛擬機內存中開始執行,當執行到User user = new User(),發現需要用到 User 類,就會將User.class加載到內存中。所以簡單的說,當需要用到哪個類時,就回去加載哪個類,Java 的自帶的核心類會在虛擬機啓動時就會加載,包括包含 main 方法的啓動類。但其實,類加載也挺複雜的,只是我瞭解的也不深,目前就理解成這樣吧,後面再深入研究。

第二階段驗證,從字面上就可以看出這個階段是來校驗加載進來的.class文件中的內容是否符合規範,畢竟編譯成.class文件後還是可以人爲的對這個文件進行修改,那如果改的亂七八糟,壓根不符合虛擬機的規範,那虛擬機就沒法執行了,所以說這一步還是比較關鍵的。至於如何驗證,還沒有研究。

準備階段我引用《深入理解 Java 虛擬機》中的一句話:準備階段是正式爲類變量分配內存並設置類變量初始值的階段,這些變量所使用的內存都將在方法區中進行分配。這也比較好理解,看下面一段代碼:

public class Test {
    public static int value = 10;
}

當需要用到這個類時,會先將這個類加載到內存中,並驗證字節碼文件的合法性。驗證通過後就會進行準備工作了,會爲這個類中的類變量分配內存空間,就是上面的 value 變量,並給一個初始值。

注意,僅包括類變量,不包括實例變量和局部變量等,並且只是給一個初始值,int 型的初始值是 0,所以準備過後,value 的值是 0,而不是 10,而真正賦值爲 10 是在初始化階段。我還在其它資料上看到,這一階段也會給這個類分配內存空間,先給類分配內存,在給它裏面的類變量分配內存。

解析階段是將常量池中的符號引用替換爲直接引用的過程,這一部分內容我還沒搞懂,所以這裏就不過多記錄了,簡單瞭解一下。

初始化階段是類加載中核心的一步了,還是以上面的代碼爲例,準備階段我們已經爲 value 變量分配了內存空間並給了初始值,現在就是真正給 value 賦值的時候,把 10 賦給了 value。如果類中還含有靜態代碼塊,也會在這一階段執行。這裏還要一點要注意,初始化類的時候,如果父類還沒加載和初始化,也會觸發父類的加載和初始化。

使用就沒什麼好說了,初始化完就可以開始使用這個對象了。

卸載是類的生命週期中的最後一階段,即將方法區中無用的類回收,而類需要同時滿足下面 3 個條件纔算無用的類:

同時滿足上述 3 個條件的類即可回收,但不一定就會回收,可通過參數配置。

下面用一張圖來簡單展示類的加載流程:

以上就是 Java 類的加載過程,當然,只是簡單的說明了一下,剛接觸,還是有很多地方不清楚,先大概有一個這樣的印象,後面再慢慢深入理解。

參考資料:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/gc8H0KOsOdohLnCvK0CIAw