深入理解java虛擬機之虛擬機類加載機制

類加載的時機

  • 類的生命週期

    • 加載
    • 連接
      • 驗證
      • 準備
      • 解析
    • 初始化
    • 使用
    • 卸載
  • 虛擬機規定必須初始化

    • 遇到new getstatic putstatic invokestatic 四個字節碼指令,如果類沒有初始化,則需要先觸發初始化。
      • 使用場景
        • 使用new 關鍵字 實例化對象
        • 讀取或者設置一個類的靜態字段
        • 調用一個類的靜態方法的時候
    • 使用java.lang.reflect 包的方法對類進行反射調用的時候
    • 初始化一個類的時候,發現其父類還沒有初始化,則觸發父類的初始化
    • 當虛擬機啓動的時候,用戶需要制定一個要執行的主類(main) 虛擬機會先初始化這個類
    • 當使用JDK 1.7的動態語言支持時,如果-個java.lang.invoke.MehodHandle實例最後的解析結果REF_ getStatic、 REF_ putStatic、 invokeStatic的方法句柄,並且這個方法句柄所對應的類沒有進行過初始化,則需要先觸發其初始化。
    • 這五種初始化稱爲對一個類的主動引用

加載

  • 加載的過程
    • 通過一個類的全限定名來獲取定義此類的二進制字節流
    • 將這個字節流所代表的靜態存儲結構轉化爲方法區的運行時數據結構
    • 在內存中生成一個代表這個類的java.lang.Class對象 作爲方法區這個類的各種數據的訪問入口

驗證

  • 連接的第一步,確保class文件的字節流都符合虛擬機的要求,而且不會危害虛擬機的安全.
  • 過程
    • 文件格式驗證
    • 元數據驗證
    • 字節碼驗證
    • 符號引用驗證

準備

  • 正式爲類變量分配內存並且設置類變量初始化的階段,這些變量所使用的內存都將在方法區中進行分配(static 變量)

解析

  • 虛擬機將常量池內的符號引用替換成直接引用
    • 符號引用
      • 用一組符號來表示所引用的對象,符號可以是任何形式的字面量,只要使用時可也準確的定位到目標。
      • 引用的目標不一定已經加載到內存中
    • 直接引用
      • 可以是直接指向目標的指針,相對偏移量或者是一個能間接定位到目標的句柄。同一個符號引用在不同虛擬機實例上翻譯出來的直接引用一般不會相同,如果有了直接引用,那麼引用的目標必定已經在內存中存在。

初始化

  • 真正執行類中定義的java程序代碼( 字節碼)
  • 因爲準備階段,變量已經賦過一次系統要求的初始值。而初始化階段 則根據程序員通過程序制定的主關計劃去初始化類變量和其他資源。
  • 初始化過程就是執行類構造器()方法的過程.
    • ()方法由編譯器自動收集類中的所有類變量的賦值動作和靜態語句塊中的語句合併產生的,編譯收集的順序是源文件中出現的順序。
    • ()與類的構造器不同,它不需要顯式地的調用父類構造器,虛擬機會保證子類的()執行之前,父類的()已經執行完畢。因此第一個執行()的一定是Object類
    • 由於父類的()方法先執行,所以父類中定義的靜態語句快要優先子類的變量賦值操作。
    • ()方法對於類或者接口來說不是必須的,如果一個類沒有靜態語句快 也沒有對變量的賦值過程,那麼編譯器可以不爲這個類產生()方法。
    • 接口中不能使用靜態語句快,但任然有變量初始化的賦值操作,因此接口和類一樣都會生成()方法,但是接口和類不同的是,執行接口的()方法不需要先執行父接口的()方法。
    • 虛擬機會保證一個類的()方法在多線程環境中被正確的加鎖、同步。

類加載

  • 通過一個類的全限定名在獲取描述此類的二進制字節流 的這個類被稱爲 類加載器。

  • 對於任意一個類,都需要由加載他的加載器和類本身來確地在虛擬機中的唯一性。

  • 雙親委派模型

    • 類加載器
      • 啓動類加載器(Bootstrap ClassLoader)
        • 主要負責加載 存放<java_home>\lib 中的或者被-Xbootclasspath參數所指定的目錄。
        • 啓動類加載器無法被java程序直接引用,使用null 代替.
      • 擴展類加載器(Extension ClassLoader)
        • 負責加載<java_home>\lib\ext 目錄的
        • 可以直接使用
      • 應用程序類加載器
        • 又稱系統類加載器
        • 負責加載用戶類路徑上的指定的類庫。
        • 默認的
    • 工作過程
      • 如果一個類加載器收到了類加載的請求,它首先不會自己嘗試去加載這個類,而是把這個請求委派給父類加載器去完成,每一層加載器都是如此,因此最後所有的加載請求都傳送到頂層的啓動類加載器。只有當父加載器反饋自己無法完成這個加載請求,子加載器纔會嘗試自己去加載。
    • 好處
      • java類隨着它的類加載器一起具備了帶優先級的層次關係。
      • 避免類的重複加載
      • 保護程序安全,防止核心API 被隨意篡改
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章