Jvm類加載的過程


Jvm類加載的過程

類加載的時機

類從被加載到虛擬機內存開始,到卸載出內存為止,整個生命周期包括:加載,驗證,准備,解析,初始化,使用和卸載
;
規定5種情況:

  • 遇到new,getstatic,putstatic或invokestatic這四條字節碼指令時,如果類沒有進行過初始化,則需要先觸發初始化
  • 使用java.lang.reflect包的方法對類進行反射調用的時候,如果類沒有進行過初始化,則需要先觸發其初始化,
  • 當初始化一個類的時候,如果發現其父類還沒有進行過初始化,則需要先觸發其父類的初始化
  • 當虛擬機啟動時,用戶需要指定一個要執行的主類(包含main方法的類),虛擬機會先初始化這個類
  • 當時用,JDK1.7的動態語言支持時,如果一個java.lang.invoke.MethodHandle實例后的解析結果是REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,並且這個方法句柄對應的類還沒有進行過初始化,則需要先觸發其初始化

類加載過程

加載

  • 加載是類加載過程的一個階段,在加載階段虛擬機需要完成三件事
    • 通過一個類的全限定名來獲取定義此類的輔而進之字節流
    • 講字節流所代表的的靜態存儲結構轉化為方法區的運行時數據結構
    • 在內存中生成一個代表這個類的java.lang.Class對象,作為方法區這個類的各種數據的訪問入口

驗證

  • 驗證就是確保Class文件的字節流中包含的信息符合當前虛擬機的要求,並且不會危害虛擬機自身的安全
    • 文件格式驗證:驗證字節流是否符合Class文件格式的規范
    • 元數據驗證:對字節碼描述的信息進行語義分析(注意:對比javac編譯階段的語義分析),以保證其描述的信息符合Java語言規范的要求
    • 字節碼驗證:通過數據流和控制流分析,確定程序語義是合法的、符合邏輯的
    • 符號引用驗證:確保解析動作能正確執行。

准備

  • 准備階段是正式為類靜態變量分配內存並設置類變量初始值的階段,這些變量所使用的內存都在方法區中進行分配
    • 這時候進行內存分配的僅包括類變量(static),而不包括實例變量,實例變量會在對象實例化時隨着對象一塊分配在Java堆中
    • 這里所設置的初始值通常情況下是數據類型默認的零值(如0、0L、null、false等),而不是被在Java代碼中被顯式地賦予的值
      public static int value = 123 //在准備階段 value的值是 0 並不是123
    
    • 如果屬性有Constant Value 屬性,那么在准備階段變量就會被初始化為所指定的值
       public static final int value = 123 // 准備階段value 的值為123
    

解析

  • 解析階段是虛擬機將常量池內的符號引用替換為直接引用的過程
    • 直接引用:直接引用可以使直接指向目標的指針,相對偏移量或是一個能間接定位到目標的句柄
    • 符號引用:符號引用以一組符號來描述所引用的目標,符號可以是任何形式的字面量,只要使用時能無歧義的定位到目標即可
      主要包含:
  • 類或接口的解析
  • 字段解析
  • 類方法解析
  • 接口方法解析

初始化

  • 初始化,為類的靜態變量賦予正確的初始值,JVM負責對類進行初始化,主要對類變量進行初始化。在Java中對類變量進行初始值設定有兩種方式:
    ①聲明類變量是指定初始值
    ②使用靜態代碼塊為類變量指定初始值
  • JVM初始化步驟:
    1、假如這個類還沒有被加載和連接,則程序先加載並連接該類
    2、假如該類的直接父類還沒有被初始化,則先初始化其直接父類
    3、假如類中有初始化語句,則系統依次執行這些初始化語句
  • 類的初始化,見開頭

結束生命周期

在如下幾種情況下,Java虛擬機將結束生命周期

  • 執行了 System.exit()方法
  • 程序正常執行結束
  • 程序在執行過程中遇到了異常或錯誤而異常終止
  • 由於操作系統出現錯誤而導致Java虛擬機進程終止

類加載器

把類加載階段的“通過一個類的全限定名來獲取描述此類的二進制字節流”這個動作交給虛擬機之外的類加載器來完成。這樣的好處在於,我們可以自行實現類加載器來加載其他格式的類,只要是二進制字節流就行,這就大大增強了加載器靈活性。

  • 啟動類加載器
  • 擴展類加載器
  • 應用程序類加載器
    • 雙親委派機制

      如果一個類加載器收到了類加載的請求,他首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去加載,每一層次的類加載器都是如此,因此所有的加載請求最終都應該傳送到頂層的啟動類加載器中,只有當父加載器反饋無法完成這個加載請求時,自家在其才會嘗試自己加載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM