JVM類載入過程

碼出地球發表於2021-10-18

JVM類載入分為5個過程:載入,驗證,準備,解析,初始化,使用,解除安裝,如下圖所示:

載入過程

載入

載入是指查詢位元組流並據此建立類的過程。

  • (1) 陣列類沒有對應的位元組流,它是由JVM根據元素型別和維度,建立的。
  • (2) 除了陣列類,其他類都是JVM藉助BootStrap ClassLoaderClassLoaderExtClassLoaderAppClassloader等類載入器來查詢位元組流並建立的。
  • (3) 在JVM中類的唯一性是由類的全名和類載入器確定的,相同的class檔案被不同的類載入器載入生成的兩個類是不同的。

連線

連線是指將建立好的類放入JVM並使之能夠很好的執行的過程。
它可分為驗證、準備、解析三個步驟。

  • (1) 驗證階段是為了保證建立的類能夠滿足JVM的約束條件,例如:jdk版本驗證。
  • (2) 準備階段的目的是為建立的類的靜態欄位分配記憶體,對靜態欄位具體的初始化會在初始化階段進行。
    部分虛擬機器在此階段還會構造跟其他類層次相關的資料結構(比如用來實現虛擬方法的動態繫結的方法表),在這個階段該類無法知道其他類、欄位及其方法的地址,因此在需要引用這些成員的時候,java編譯器會生成一個符號引用,在執行階段該引用才能夠定位到具體的地址。
  • (3) 解析階段的目的是將符號引用解析成實際引用,如果符號引用指向一個未被載入的成員,那個將觸發JVM對這個類的載入。
    JVM規範並沒有要求在連線過程中執行解析工作,它僅僅規定如果某些欄位使用了符號引用,那麼在執行這些位元組碼之前需要先完成對這些富豪飲用的解析。

初始化

初始化的目的是為標記為常量的欄位賦值,以及執行clinit方法的過程。

在初始化一個靜態欄位的時候,我們可以再宣告時直接賦值,也可以在靜態程式碼塊中對其進行賦值。
如果直接賦值的欄位被final所修飾,並且欄位為基本資料型別和String型別,那麼該欄位會被編譯標記為常量值,其初始化直接由JVM完成。除此之外的所有直接賦值和靜態程式碼塊中賦值操作,會被java編譯器放到clinit方法中。

什麼時候需要對類進行初始化?

(1) 虛擬機器啟動的時候,初始化使用者指定的主類。
(2) 使用new該類例項化物件的時候。
(3) 訪問靜態欄位或靜態方法時,初始化靜態欄位或靜態方法所在類。
(4) 子類初始化會觸發父類初始化。
(5) 如果介面定義了default方法,那麼實現該介面的類初始化會觸發該介面的初始化。
(6) 使用反射API的時候。
(7) 當使用JDK1.7的動態語言支援時,如果一個java.invoke.MethodHandle例項最後的解析結果REF_getStatic、REF_putStatic、REF_invokeStatic的方法控制程式碼,並且這個方法控制程式碼所對應的類沒有進行過初始化,則需要先觸發其初始化。



參考連結:
nomico271.github.io/2017/07/07/…

相關文章