天天看點

【JVM】一文讀懂類的加載階段什麼是類加載機制類加載器

什麼是類加載機制

虛拟機把描述類的資料從class檔案加載到記憶體,并對資料進行校驗,轉換解析和初始化,最終形成可以被虛拟機直接使用的Java類型,這就是虛拟機的類加載機制。

類的加載和連接配接過程都是在程式運作期間完成的,這樣在類加載時會增加一些性能開銷,但是提高了Java應用程式的靈活性。

類的生命周期

整個生命周期包括加載、驗證、準備、解析、初始化、使用和解除安裝七個階段,其中驗證,準備,解析統稱為連接配接。其中加載、驗證、準備、初始化和解除安裝五個過程順序是固定的,解析某些情況下可以在初始化之後。

加載

是将類的位元組碼載入到方法區中,如果這個類還有父類沒有加載,先要加載父類,加載和連接配接可能是交替進行的。加載階段虛拟機完成下面三件事情:

  1. 通過一個類的權限定名來擷取定義此類的二進制位元組流。
  2. 将這個位元組流所代表的靜态存儲結構轉化為方法區的運作時資料結構。
  3. 在Java堆中生成一個代表這個類的java.lang.Class對象,作為方法區這些資料的通路入口。

驗證

驗證位元組碼的格式是否正确,是否符合虛拟機的要求,并且不會危害虛拟機安全。

  • 檔案格式驗證
  • 中繼資料驗證
  • 位元組碼驗證
  • 符号引用驗證

準備

準備階段是正式為靜态變量配置設定記憶體空間并設定預設值的階段,這些記憶體在JDK1.6之前将配置設定在方法區,現在配置設定在堆中。

靜态變量配置設定空間和指派時兩個步驟,配置設定空間在準備階段完成,指派在初始化階段完成。而final修飾的變量的指派時發生在準備階段。

解析

虛拟将常量池中的符号引用替換為直接引用。

符号引用:符号引用以一組符号來描述所引用的目标, 符号可以是任何形式的字面量, 隻要使用時能夠無歧義的定位到目标即可. 例如, 在Java中, 一個Java類将會編譯成一個class檔案. 在編譯時, Java類并不知道所引用的類的實際位址, 是以隻能使用符号引用來代替. 

直接引用就是引用的真實位址。

初始化

初始化即調用 <cinit>()v 方法,虛拟機會保證這個類的 “構造方法” 的線程安全。

會被初始化的情況:

  • main方法的所在類總是會被初始化
  • 首次通路這個類的靜态變量或者靜态方法時
  • 子類初始化時但是父類還沒有初始化
  • 子類通路父類的靜态變量,隻會觸發父類的初始化,子類不會初始化

不會被初始化的情況:

  • 通路類的 static final 靜态常量不會觸發初始化
  • 類對象 .class 不會觸發初始化(加載階段已經觸發)
  •  建立該類的數組不會觸發初始化
  • 類加載器的loadClass方法不會觸發初始化(ClassLoader隻會進行類的加載,不會解析和初始化)

類加載器

絕大多數Java程式都會使用到一下四種系統提供的類加載器:

  • 啟動類加載器
  • 擴充類加載器
  • 應用程式類加載器
  • 自定義類加載器

啟動類加載器

啟動類加載器主要加載的是JVM自身需要的類,這個類加載使用C++語言實作的,是虛拟機自身的一部分,它負責将 <JAVA_HOME>/lib路徑下的核心類庫或-Xbootclasspath參數指定的路徑下的jar包加載到記憶體中,注意必由于虛拟機是按照檔案名識别加載jar包的,如rt.jar,如果檔案名不被虛拟機識别,即使把jar包丢到lib目錄下也是沒有作用的(出于安全考慮,Bootstrap啟動類加載器隻加載包名為java、javax、sun等開頭的類)。

擴充類加載器

它負責加載

<JAVA_HOME>/lib/ext

目錄下或者由系統變量-Djava.ext.dir指定位路徑中的類庫。由Java語言實作,父類加載器為null。

應用程式類加載器

又稱系統類加載器。它負責在JVM啟動時加載來自Java指令的-classpath選項、java.class.path系統屬性,或者CLASSPATH換将變量所指定的JAR包和類路徑。程式可以通過ClassLoader的靜态方法getSystemClassLoader()來擷取系統類加載器。如果沒有特别指定,則使用者自定義的類加載器都以此類加載器作為父加載器。由Java語言實作,父類加載器為ExtClassLoader。

雙親委派機制

【JVM】一文讀懂類的加載階段什麼是類加載機制類加載器

雙親翻譯為上級更容易了解,雙親委派模式中的父子關系并非通常所說的類繼承關系,而是采用組合關系來複用父類加載器的相關代碼。

如果一個類加載器收到了類加載請求,它并不會自己先去加載,而是把這個請求委托給父類的加載器去執行,如果父類加載器還存在其父類加載器,則進一步向上委托,請求最終将到達頂層的啟動類加載器,如果父類加載器可以完成類加載任務,就成功傳回,倘若父類加載器無法完成此加載任務,子加載器才會嘗試自己去加載,這就是雙親委派模式,即每個兒子都很懶,每次有活就丢給父親去幹,直到父親說這件事我也幹不了時,兒子自己想辦法去完成。

雙親委派模式的優點:

Java類随着它的類加載器一起具備了一種帶有優先級的層次關系,通過這種層級關可以避免類的重複加載,當父親已經加載了該類時,就沒有必要子ClassLoader再加載一次。

jvm