JVM最佳學習筆記<四>---虛擬機類加載機制

前提

本筆記參照了周志明《深刻理解Java虛擬機:JVM高級特性與最佳實踐》第三版,讀完以後受益不淺,讓我對Java虛擬機有了一個深入的認識,這也是Jvm書籍中最好的讀物之一。java

1. 概述

虛擬機把描述類的數據從Class文件加載到內存,並對數據進行校驗、轉換解析和初始化,最終造成能夠被虛擬機直接使用的Java類型,這就是虛擬機的類加載機制。mysql

在Java語言中,類型的加載、鏈接和初始化過程都是在程序運行期間完成的。sql

2. 類加載的時機

類從加載到虛擬機內存開始,到卸載出內存爲止,它的整個生命週期包括:加載、驗證、準備、解析、初始化、使用和卸載7個階段。其中驗證、準備、解析3個部分統稱爲鏈接。以下圖所示:數據庫

3. 類加載的過程

加載

在加載階段,虛擬機須要完成如下3個事情:數組

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

特殊狀況:
對於數組類而言,狀況有所不一樣,數組類自己不經過類加載器建立,它是由Java虛擬機直接建立的。安全

驗證

驗證是鏈接階段的第一步,這一階段的目的是爲了確保Class文件的字節流中包含的信息符合當前虛擬機的要求,而且不會危害虛擬機自身的安全
驗證階段大體上會完成如下4個階段的校驗動做:數據結構

  • 文件格式校驗(驗證是否符合Class文件格式的規範)
  • 元數據校驗(驗證描述的信息是否符合Java語言規範)
  • 字節碼校驗(驗證程序語義是否合法、符合邏輯的)
  • 符號引用校驗(確保解析動做可以正常執行,好比出現java.lang.NoSuchMethodError)

準備

準備階段是正式爲類變量分配內存並設置類變量初始值的階段,這些變量所使用的內存都將在方法區中進行分配。指針

假定一個類變量的定義爲:code

public static int value = 123;

變量value在準備階段事後的初始值爲0而不是123。對象

基本數據類型的零值 |數據類型|零值| |:---:|:---:| |int|0| |long|0L| |short|(short)0| |char|'\u0000'| |byte|(byte)0| |boolean|false| |float|0.0f| |double|0.0d| |reference|null|

注:單精度和精度區別:單精度float是4字節,雙精度double是8字節

解析

解析階段是虛擬機將常量池內的符號引用替換爲直接引用的過程。

  • 符號引用:是以一組符號來描述所引用的目標,符號能夠是任何形式的字面量,只要使用時無歧義地定位到目標便可。
  • 直接引用:是直接指向目標的指針、相對偏移量或是一個能間接定位到目標的句柄

初始化

初始化階段是執行類構造器<clinit>()方法的過程。

<clinit>()方法是由編譯器自動收集類中的全部類變量的賦值動做和靜態語句塊(static{}塊)中的語句合併產生的,編譯器收集的順序是由語句在源文件中出現的順序所決定的,靜態語句塊中只能訪問到定義在靜態語句塊以前的變量。

4. 類加載器

類與類加載器

對於任意一個類,都須要由加載它的類加載器和這個類自己一同確立其在Java虛擬機中的惟一性,每個類加載器,都擁有一個獨立的類名稱空間。===> 比較兩個類是否「相等」,只要類加載器不一樣,那這兩個類一定不想等,即便是同一個Class文件,被同一個虛擬機加載。

雙親委派模型

從Java虛擬機的角度來說,只存在兩種不一樣的類加載器:

  • 啓動類加載器(BootStrap ClassLoader),使用C++語言實現,是虛擬機自己的一部分
  • 全部其餘的類加載器,都由Java語言實現,獨立虛擬機外部,而且都繼承自抽象類java.lang.ClassLoader

雙親委派模型的工做過程

若是一個類加載器收到了類加載的請求,它首先不會本身去嘗試加載這個類,而是把這個請求委派給父親加載器去完成。以下圖所示:

雙親委派模型意義:

  • 系統類防止內存中出現多份一樣的字節碼
  • 保證Java程序安全穩定運行

破壞雙親委派模型

爲何須要破壞雙親委派?

由於在某些狀況下父類加載器須要委託子類加載器去加載class文件。受到加載範圍的限制,父類加載器沒法加載到須要的文件。

Driver接口爲例,因爲Driver接口定義在jdk當中的,而其實現由各個數據庫的服務商來提供,好比mysql的就寫了MySQL Connector,那麼問題就來了,DriverManager(也由jdk提供)要加載各個實現了Driver接口的實現類,而後進行管理,可是DriverManager由啓動類加載器加載,只能記載JAVA_HOME的lib下文件,而其實現是由服務商提供的,由系統類加載器加載,這個時候就須要啓動類加載器來委託子類來加載Driver實現,從而破壞了雙親委派。

5. 本章小結

本章介紹了類加載過程的「加載」、「驗證」、「準備」、「解析」、「初始化」 5個階段中虛擬機進行了哪些動做,還介紹了類加載器的工做原理及其對虛擬機的意義。

相關文章
相關標籤/搜索