天天看點

jvm的類加載機制總結

類的加載機制分為如下三個階段:加載,連接配接,初始化。其中連接配接又分為三個小階段:驗證,準備,解析。

jvm的類加載機制總結

加載階段

将類的.class檔案中的二進制資料讀入到記憶體中,将其放在運作時資料區的方法區内,然後再堆内建立一個class對象,用來封裝類在方法區内的資料結構。

加載class檔案的方式:

從本地系統中直接加載

通過網絡下載下傳.class檔案

從zip,jar等歸檔檔案中加載.class檔案

從專有資料庫中提取.class檔案

将Java源檔案動态編譯為.class檔案

jvm的類加載機制總結

類的加載最終産品是位于堆中的class對象。Class對象封裝了類在方法區内的資料結構,并且向java程式員提供了通路方法區内的資料結構和接口。

類加載并不需要等到某個類被主動使用的時候才加載,jvm規範允許類加載器在預料到某個類要被使用的時候就預先加載。如果預先加載過程中報錯,類加載器必須在首次主動使用的時候才會報錯。如果類一直沒有被使用,就不會報錯。

驗證階段

此階段驗證的内容如下

類檔案的結構檢查:

確定類檔案遵從java類檔案的固定頭格式,就像平時做檔案上傳驗證檔案頭一樣。還會驗證檔案的主次版本号,確定目前class檔案的版本号被目前的jvm相容。驗證類的位元組流是否完整,根據md5碼進行驗證。

語義檢查:

檢查這個類是否存在父類,父類是否合法,是否存在。

檢查該類是不是final的,是否被繼承了。被final修飾的類是不允許被繼承的。

檢查該類的方法重載是否合法。

檢查類方法翻譯後的位元組碼流是否合法。

引用驗證,驗證目前類使用的其他類和方法是否能夠被順利找到。

準備階段

通過驗證階段之後,開始給類的靜态變量配置設定記憶體,設定預設的初始值。類變量的記憶體會被配置設定到方法區中,執行個體變量會被配置設定到堆記憶體中。準備階段的變量會賦予初始值,但是final類型的會被賦予它的值,可以了解為編譯的時候,直接編譯成常量賦給。如果是一個int類型的變量會配置設定給他4個位元組的記憶體空間,并賦予值為0。如果是long會賦予給8個位元組,并賦予0。

解析階段

解析階段會把類中的符号引用替換成直接引用。比如Worker類的gotoWork方法會引用car類的run方法。

jvm的類加載機制總結

在work類的二進制資料,包含了一個Car類的run的符号引用,由方法的全名和相關描述符組成。解析階段,java虛拟機會把這個符号引用替換成一個指針,該指針指向car類的run方法在方法區中的記憶體位置,這個指針就是直接引用。

初始化階段

類的初始化階段就是對壘中所有變量賦予正确的值,靜态變量的指派和成員變量的指派都在此完成。初始化的順序參考上方的整理。

初始化有幾點需要注意

如果類還沒有被加載和連接配接,就先進行加載和連接配接。如果存在直接的父類,父類沒有被初始化,則先初始化父類。