天天看點

JVM類加載機制與對象的生命周期

轉載請注明原文位址:http://www.cnblogs.com/ygj0930/p/6536048.html 

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

    Java天生的可動态擴充的語言特性就是依賴運作期的動态加載和動态連接配接實作的。

    一:類的生命周期

    類的生命周期包括7個部分:加載——驗證——準備——解析——初始化——使用——解除安裝

    其中,驗證——準備——解析  稱為連接配接階段。除了解析外,其他階段是順序發生的,而解析可以與這些階段交叉進行,因為Java支援動态綁定(晚期綁定),需要運作時才能确定具體類型。

    二:類的初始化觸發

    類的加載機制沒有明确的觸發條件,但是有5種情況下必須對類進行初始化,那麼 加載——驗證——準備 就必須在此之前完成了。

    1:new、getstatic、putstatic、invokestatic這4個  位元組碼指令  時對類進行初始化(即:執行個體化對象、讀寫靜态對象、調用靜态方法時,進行類的初始化);

    2:使用反射機制對類進行調用時,進行類的初始化;

    3:初始化一個類,其父類沒有初始化時,先初始化其父類;

    4:虛拟機啟動時,初始化一個執行主類;

    5:使用JDK1.7的動态語言支援時,如果MethodHandle執行個體的解析結果為REF_getstatic、REF_putstatic、REF_invokestatic的方法句柄(即:讀寫靜态對象或者調用靜态方法),則初始化該句柄對應類;

    一般,以上5種情況最常見的是前三種:執行個體化對象、讀寫靜态對象、調用靜态方法、反射機制調用類、調用子類觸發父類初始化。

    三:類的加載過程

    從使用者角度來說,類(對象)的生命周期隻需籠統了解為“加載——使用——解除安裝”即可,無需太過深入。是以,這裡的類加載過程就是我們說的 加載——驗證——準備——解析——初始化  這五個使用前的階段。

    1:加載

       加載階段,虛拟機需要完成三件事:通過類名字擷取類的二進制位元組流——将位元組流的内容轉存到方法區——在記憶體中生成一個Class對象作為該類方法區資料的通路入口。

       其中,第一步:通過類名擷取類的二進制位元組流是通過類加載器來完成的。其加載過程使用“雙親委派模型”:

       類加載器的層次結構為:

JVM類加載機制與對象的生命周期

       啟動類加載器:加載系統環境變量下JAVA_HOME/lib目錄下的類庫。

       擴充類加載器:加載JAVA_HOME/lib/ext目錄下的類庫。

       應用程式類加載器(系統類加載器):加載使用者類路徑Class_Path指定的類庫。(我們可以在使用第三方插件時,把jar包添加到ClassPath後就是使用了這個加載器)

       自定義加載器:如果需要自定義加載時的規則(比如:指定類的位元組流來源、動态加載時性能優化等),可以自己實作類加載器。

       雙親委派模型是指:當一個類加載器收到類加載請求時,不會直接加載這個類,而是把這個加載請求委派給自己父加載器去完成。如果父加載器無法加載時,子加載器才會去嘗試加載。

       采用雙親委派模型的原因:避免同一個類被多個類加載器重複加載。

    2:驗證

       確定class檔案的二進制位元組流中包含的資訊符号虛拟機要求,包括:檔案格式驗證、中繼資料驗證(資料語義分析)、位元組碼驗證(資料流語義合法性)、符号引用驗證(符号引用的比對性校驗,確定解析能正确執行)

    3:準備

       為類變量(靜态變量)在方法區配置設定記憶體,并設定零值。注意:這裡是類變量,不是執行個體變量,執行個體變量是對象配置設定到堆記憶體時根據運作時動态生成的。

    4:解析

       把常量池中的符号引用解析為直接引用:根據符号引用所作的描述,在記憶體中找到符合描述的目标并把目标指針指針傳回。

    5:初始化

       真正開始執行Java程式代碼,該步執行<clinit>方法根據代碼指派語句,對 類變量和其他資源  進行初始化指派。

       <clinit>方法:編譯器自動收集類中所有  類變量的指派語句和靜态語句合并而成,收集的順序是在程式代碼出現的順序。是以,靜态語句中隻能通路到定義在靜态語句塊之前的變量,在其之後的變量可以指派(相當于建立并指派了)但不可以通路(因為還沒出現)。

       注:由此步我們就可以得知,我們在分析向上轉型的例子時的程式代碼的運作順序了:父類靜态内容——子類靜态内容——父類構造——子類構造——子類方法 。

    在經曆了上面5步“加載”階段後,才真正地可以使用class對象或者使用執行個體對象。使用過後,不再需要用到該類的class對象或者執行個體對象時,就會把類解除安裝掉(發生在方法區的垃圾回收:無用類的解除安裝)。

    四:對象的生命周期

     對象是由類建立出來的,是以對象的生命周期就是包含在類的生命周期中:

     類加載(5步)——建立類的執行個體對象——使用對象——對象回收——類解除安裝