本筆記參照了周志明《深刻理解Java虛擬機:JVM高級特性與最佳實踐》
第三版,讀完以後受益不淺,讓我對Java虛擬機有了一個深入的認識,這也是Jvm書籍中最好的讀物之一。java
虛擬機把描述類的數據從Class文件加載到內存,並對數據進行校驗、轉換解析和初始化,最終造成能夠被虛擬機直接使用的Java類型,這就是虛擬機的類加載機制。mysql
在Java語言中,類型的加載、鏈接和初始化過程都是在程序運行期間完成的。sql
類從加載到虛擬機內存開始,到卸載出內存爲止,它的整個生命週期包括:加載、驗證、準備、解析、初始化、使用和卸載7個階段。其中驗證、準備、解析3個部分統稱爲鏈接。以下圖所示:數據庫
在加載階段,虛擬機須要完成如下3個事情:數組
java.lang.Class
對象,做爲方法區這個類的各類數據的訪問入口。特殊狀況:
對於數組類而言,狀況有所不一樣,數組類自己不經過類加載器建立,它是由Java虛擬機直接建立的。安全
驗證是鏈接階段的第一步,這一階段的目的是爲了確保Class文件的字節流中包含的信息符合當前虛擬機的要求,而且不會危害虛擬機自身的安全。
驗證階段大體上會完成如下4個階段的校驗動做:數據結構
準備階段是正式爲類變量分配內存並設置類變量初始值的階段,這些變量所使用的內存都將在方法區中進行分配。指針
假定一個類變量的定義爲: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{}塊)中的語句合併產生的,編譯器收集的順序是由語句在源文件中出現的順序所決定的,靜態語句塊中只能訪問到定義在靜態語句塊以前的變量。
對於任意一個類,都須要由加載它的類加載器和這個類自己一同確立其在Java虛擬機中的惟一性,每個類加載器,都擁有一個獨立的類名稱空間。===> 比較兩個類是否「相等」,只要類加載器不一樣,那這兩個類一定不想等,即便是同一個Class文件,被同一個虛擬機加載。
從Java虛擬機的角度來說,只存在兩種不一樣的類加載器:
若是一個類加載器收到了類加載的請求,它首先不會本身去嘗試加載這個類,而是把這個請求委派給父親加載器去完成。以下圖所示:
由於在某些狀況下父類加載器須要委託子類加載器去加載class文件。受到加載範圍的限制,父類加載器沒法加載到須要的文件。
以
Driver
接口爲例,因爲Driver
接口定義在jdk當中的,而其實現由各個數據庫的服務商來提供,好比mysql
的就寫了MySQL Connector
,那麼問題就來了,DriverManager
(也由jdk提供)要加載各個實現了Driver
接口的實現類,而後進行管理,可是DriverManager
由啓動類加載器加載,只能記載JAVA_HOME
的lib下文件,而其實現是由服務商提供的,由系統類加載器加載,這個時候就須要啓動類加載器來委託子類來加載Driver
實現,從而破壞了雙親委派。
本章介紹了類加載過程的「加載」、「驗證」、「準備」、「解析」、「初始化」 5個階段中虛擬機進行了哪些動做,還介紹了類加載器的工做原理及其對虛擬機的意義。