【JVM】類加載時機與過程

虛擬機把描述類的數據從class文件加載到內存,並對數據進行校驗、轉換解析和初始化,最終形成可以被虛擬機直接使用的Java類型,這就是虛擬機的類加載機制。下面來總結梳理類加載的五個階段。

類加載發生在程序運行期間,會有一些性能開銷,但是會提供靈活性,Java動態擴展的特性就是依賴運行時期動態加載和動態連接特點

類加載分爲五個階段:

  1. 加載
  2. 驗證
  3. 準備
  4. 解析
  5. 初始化

後四個階段統稱爲“連接”階段

加載

加載階段,虛擬機完成以下三件事:

  • 通過一個類的全限定名來獲取此類的二進制字節流(即class文件);
  • 將字節流的靜態存儲結構轉化爲方法區的運行時數據結構;
  • 內存中生成一個代表這個類的java.lang.Class對象,作爲方法區這個類的各種數據的訪問接口;

注意

  1. 虛擬機規範中未規定方法區中的運行時數據結構,由虛擬機自行定義;
  2. 實例化的java.lang.Class對象未明確規定存儲在堆中,HotSpot中的class對象存在方法區中

加載階段尚未完成時,後續連接解讀那可能已經開始

驗證

驗證階段主要是爲了確保class文件字節流中的信息符合虛擬機要求,不會危害虛擬機自身安全。主要有以下幾種格式驗證:

  • 文件格式驗證:驗證是否符合Class文件規範
  • 元數據驗證:字節碼語義分析,是否符合Java語言要求
  • 字節碼驗證:驗證類的方法體,保證運行不會產生危害
  • 符號引用驗證:驗證符號引用是否能找到對應的類,是否具有訪問權限等

對於反覆使用和驗證過的代碼,可以使用-Xverify:none 可以關閉類驗證措施,以縮短類加載時間。因爲平時開發中idea和eclipse等工具的驗證功能很完善,能保證代碼準確。

準備

爲static變量分配空間,不包括實例變量,實例變量會在對象實例化時和對象一起分配在堆中,

  • static分配空間在“準備”階段(在方法區中分配),賦值在“初始化”階段。例如 public static int value = 123 會在準備階段設置初始值0,在初始化階段賦值“123”;
  • static+final修飾基本數據類型和字符串常量時,分配空間和賦值都是在準備階段,可以藉此優化代碼
  • static+final修飾引用類型,即用new初始化時,是在構造方法中分配空間和賦值,即在初始化階段完成

解析

將常量池中的符號引用解析爲直接引用。那麼問題來了,什麼是符號引用和直接引用:

  • 符號引用:描述目標的符號,與虛擬機內存佈局無關,以字面量的形式明確定義在class文件中。Java虛擬機內存佈局各不相同,但是符號引用必須一致。Java類編譯時,不知道引用的類的實際地址,因此使用符號引用。
  • 直接引用:直接指向目標的指針、相對偏移量或是一個能間接定位到目標的句柄。同一個符號引用在不同虛擬機實例上翻譯出來的直接引用一般不會相同。

解析動作針對類或接口、字段、類方法、接口方法、方法類型、方法句柄和調用點限定符7類符號引用進行。

初始化:

常說的“類加載時機”與“初始化時機”一一對應。因爲要進入初始化階段,就必須要完成加載、驗證、準備、解析等階段。
初始化發生時機如下:

  • main方法所在類總是會被首先初始化
  • 首次訪問這個類的靜態變量或靜態方法時會導致初始化
  • 子類初始化會聯動父類初始化
  • 通過子類訪問父類靜態變量,只會觸發父類初始化
  • Class.forName
  • new會導致初始化

以下情況不會導致類初始化的情況:

  • static final不會觸發初始化
  • 訪問類對象.class
  • 創建該類的數組
  • 類加載器的loadClass方法
  • Class.forName的參數2爲false

初始化階段實際上是執行類構造器<clinit>()方法的過程。<clinit>()會根據源文件中順序收集類中所有類變量賦值動作和static塊語句

注意:static塊能訪問代碼塊之前的變量,之後的變量可以賦值,但不能訪問

<clinit>()方法的執行有如下特點:

  • 第一個執行clinit方法的一定是Object類
  • 父類中靜態語句塊一定優先於子類
  • 如果類中沒有static方法和變量,不會產生clinit方法
  • 接口中如果有static變量,也會生成clinit,但是子接口不會執行父接口中的clinit,接口的實現類也不會調用接口中的clinit
  • 多線程時,只會有一個線程會去執行clinit,會加鎖,保證線程安全
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章