1. 程式人生 > >JVM的類載入機制和載入過程

JVM的類載入機制和載入過程

一、虛擬機器的類載入機制

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

    與那些在編譯器需要進行連線工作的語言不同,在Java語言中,型別的載入和連線過程都是在程式執行期間完成的,這樣會在類載入時稍微增加一些效能開銷,但是卻能為Java應用程式提供高度的靈活性,Java中可以天生動態擴充套件的語言特性就是依賴執行期動態載入和動態連線這個特點實現的。

二、類載入的時機

    類從被載入到虛擬機器記憶體中開始,到卸載出記憶體為止,它的整個生命週期包括:載入、驗證、準備、解析、初始化、使用和解除安裝七個階段。其中驗證、準備和解析三個部分統稱為連線,這七個階段的發生順序為:


    其中載入、驗證、準備、初始化和解除安裝這五個階段的順序是確定的,類的載入過程必須按照這種順序按部就班的開始,而解析階段不一定,它在某些情況可以在初始化階段之後開始,這是為了支援Java語言的執行時繫結。對於初始化階段,虛擬機器規範則是嚴格規定了有且只有四種情況必須立即對類進行初始化:

    1、遇到new、getstatic、putstatic或invokestatic這四條位元組碼指令時,如果類沒有進行初始化,則需要先出發初始化;

    2、使用java.lang.reflect包的方法對類進行反射呼叫的時候,如果類沒有進行初始化,則需要先出發初始化;

    3、當初始化一個類時,如果發現其父類沒有進行過初始化,則需要先出發其父類的初始化;

    4、當虛擬機器啟動時,使用者需要指定一個要執行的主類(包含main()方法的那個類),虛擬機器會先初始化這個主類。

三、類的載入過程

    1、載入

    載入階段是類載入過程中的一個階段,在載入階段,虛擬機器要完成三件事情:

    1.1、通過一個類的全限定名來獲取定義此類的二進位制位元組流

    1.2、將這個位元組流所代表的靜態儲存結構轉化為方法區的執行時資料結構

    1.3、在Java堆中生成一個代表這個類的java.lang.Class物件,作為方法區這些資料的訪問入口

    2、驗證

    驗證是連線階段的第一步,這一階段的目的是為了確保Class檔案的位元組流中包含的資訊符合當前虛擬機器的要求,並且不會危害虛擬機器自身的安全,校驗過程包含檔案格式驗證、元資料驗證、位元組碼驗證和符號引用驗證。

    3、準備

    準備階段是正式為類變數分配記憶體並設定類變數初始值的階段這些記憶體都將在方法區中進行分配。這個時候進行記憶體分配的僅包括類變數(被static修飾的變數),而不包括例項變數,例項變數將會在物件例項化時隨著物件一起分配到Java堆中;這裡的初始值通常情況下是資料型別的零值。

    4、解析

    解析階段是虛擬機器將常量池內的符號引用替換為直接引用的過程,符號引用是指以一組符號來描述所引用的目標,直接引用是指直接指向目標的指標、相對偏移量或者是能間接定位到目標的控制代碼。

    5、初始化

    初始化階段是類載入過程中的最後一步,這個階段才真正開始執行類中定義的Java程式程式碼(或者說是位元組碼)。

四、類載入器

    從虛擬機器的角度來說,類載入器分為兩種:一種是啟動類載入器,這是使用c++語言實現的,是虛擬機器自身的一部分;另外一種就是所有其他的類載入器,這些類載入器是由Java語言實現的,獨立於虛擬機器外部,並且全部繼承自抽象類java.lang.ClassLoader。但對於Java開發人員來講,絕大部分Java程式都會使用到以下三種系統提供的類載入器:

    1、啟動類載入器(Bootsrap ClassLoader):這個類載入器負責將存放在<JAVA_HOME>\lib目錄中的,或者被-Xbootclasspath引數所指定的路徑中的,並且是虛擬機器識別的類庫載入到虛擬機器記憶體中,啟動類載入器無法被Java程式直接引用。

    2、擴充套件類載入器(Extension ClassLoader):它負責載入<JAVA_HOME>\lib\ext目錄中的,或者被java.ext.dirs系統變數所指定的路徑中的所有類庫,開發者可以直接使用擴充套件類載入器

    3、應用類載入器(Application ClassLoader):它負責載入使用者類路徑(ClassPath)上所指定的類庫,開發者可以直接使用這個類載入器,如果應用程式中沒有自定義過自己的類載入器,一般情況下這個就是程式中預設的類載入器。

五、類載入器的雙親委派模型


    雙親委派模型除了要求頂層的啟動類載入器外,其餘的類載入器都應當有自己的父類載入器,雙親委派模型的工作過程是:如果一個類載入器收到了類載入請求,它首先自己不會嘗試載入這個類,而是把這個請求委派給父類載入器去完成,每一層次的類載入器都是如此,因此所有的載入請求最終都應該傳送到頂層的啟動類載入器,只有當父載入器反饋自己無法完成這個載入請求時,子載入器才會嘗試自己去載入。