標籤:做了 bootstrap span 指標 ssl 連結 並且 ade pat
1,類的載入過程;
JVM將類載入過程分為三個步驟:裝載(load),連結(link)和初始化(initialize),其中連結又分為三個步驟;
驗證(varification),準備(Preparation),和解析(Resolution);如
其實 類從被載入到虛擬機器記憶體中開始,直到卸載出記憶體為止,它的整個生命週期包括了:載入、驗證、準備、解析、初始化、使用和卸載這7個階段。其中,驗證、準備和解析這三個部分統稱為串連(linking)。
其中,載入、驗證、準備、初始化和卸載這五個階段的順序是確定的,類的載入過程必須按照這種順序按部就班的“開始”(僅僅指的是開始,而非執行或者結束,因為這些階段通常都是互相交叉的混合進行,通常會在一個階段執行的過程中調用或者啟用另一個階段),而解析階段則不一定(它在某些情況下可以在初始化階段之後再開始,這是為了支援Java語言的運行時綁定。
a:裝載:裝載 階段 是類載入 的第一個階段,在此階段虛擬機器要 完成三件事情
1、 通過一個類的全限定名來擷取定義此類的二進位位元組流,也就是尋找並載入類的位元據;。
2、 將這個位元組流所代表的靜態儲存結構轉化為方法區的運行時資料結構。
3、 在Java堆中產生一個代表這個類的java.lang.Class對象,作為方法區這些資料的訪問入口。
載入階段即可以使用系統提供的類載入器在完成,也可以由使用者自訂的類載入器來完成。
載入階段與串連階段的部分內容(如一部分位元組碼檔案格式驗證動作)是交叉進行的,載入階段尚未完成,串連階段可能已經開始。
JVM在記憶體 中的 表現形式:
b 驗證:
驗證是串連階段的第一步,這一階段的目的是為了確保Class檔案的位元組流中包含的資訊符合當前虛擬機器的要求,並且不會危害虛擬機器自身的安全。
Java語言本身是相對安全的語言,使用Java編碼是無法做到如訪問數組邊界以外的資料、將一個對象轉型為它並未實現的類型等,如果這樣做了,
編譯器將拒絕編譯。但是,Class檔案並不一定是由Java源碼編譯而來,可以使用任何途徑,
包括用十六進位編輯器(如UltraEdit)直接編寫。如果直接編寫了有害的“代碼”(位元組流),而虛擬機器在載入該Class時不進行檢查的話,就有可能危害到虛擬機器或程式的安全。
不同的虛擬機器,對類驗證的實現可能有所不同,但大致都會完成下面四個階段的驗證:
c 準備:
備階段是為類的靜態變數分配記憶體並將其初始化為預設值,這些記憶體都將在方法區中進行分配。
準備階段不分配類中的執行個體變數的記憶體,執行個體變數將會在對象執行個體化時隨著對象一起分配在Java堆中。
public static int value=123;//在準備階段value初始值為0 。在初始化階段才會變為123 。
d 解析:
解析階段是虛擬機器將常量池內的符號引用替換為直接引用的過程。
符號引用(Symbolic Reference):符號引用以一組符號來描述所引用的目標,符號可以是任何形式的字面量,只要使用時能無歧義地定位到目標即可。符號引用與虛擬機器實現的記憶體布局無關,引用的目標並不一定已經載入到記憶體中。
直接引用(Direct Reference):直接引用可以是直接指向目標的指標、相對位移量或是一個能間接定位到目標的控制代碼。直接引用是與虛擬機器實現的記憶體布局相關的,如果有了直接引用,那麼引用的目標必定已經在記憶體中存在。
e 初始化:
類初始化是類載入過程的最後一步,前面的類載入過程,除了在載入階段使用者應用程式可以通過自訂類載入器參與之外,其餘動作完全由虛擬機器主導和控制。到了初始化階段,才真正開始執行類中定義的Java程式碼。
初始化階段是執行類構造器<clinit>()方法的過程。<clinit>()方法是由編譯器自動收集類中的所有類變數的賦值動作和靜態語句塊(static{}塊)中的語句合并產生的。
2,關於類的 初始化:什麼時候才能觸發初始化?
也就是 什麼情況下需要開始類載入過程的第一個階段:"載入"。虛擬機器規範中並沒強行約束,這點可以交給虛擬機器的的具體實現自由把握,
但是對於初始化階段虛擬機器規範是嚴格規定了如下幾種情況,如果類未初始化會對類進行初始化。
- 建立類的執行個體
- 訪問類的靜態變數(除常量【被final修辭的靜態變數】原因:常量一種特殊的變數,因為編譯器把他們當作值(value)而不是域(field)來對待。如果你的代碼中用到了常變數(constant variable),編譯器並不會產生位元組碼來從對象中載入域的值,而是直接把這個值插入到位元組碼中。這是一種很有用的最佳化,但是如果你需要改變final域的值那麼每一塊用到那個域的代碼都需要重新編譯。
- 訪問類的靜態方法
- 反射如(Class.forName("my.xyz.Test"))
- 當初始化一個類時,發現其父類還未初始化,則先出發父類的初始化
- 虛擬機器啟動時,定義了main()方法的那個類先初始化
以上情況稱為稱對一個類進行
“主動引用”,除此種情況之外,均不會觸發類的初始化,稱為
“被動引用”介面的載入過程與類的載入過程稍有不同。介面中不能使用static{}塊。當一個介面在初始化時,並不要求其父介面全部都完成了初始化,只有真正在使用到父介面時(例如引用介面中定義的常量)才會初始化。 3,關於 類載入器 JVM的類載入是通過ClassLoader及其子類來完成的,類的層次關係和載入順序可以由來描述:
1)Bootstrap ClassLoader
負責載入$JAVA_HOME中jre/lib/rt.jar裡所有的class,由C++實現,不是ClassLoader子類
2)Extension ClassLoader
負責載入java平台中擴充功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目錄下的jar包
3)App ClassLoader
負責記載classpath中指定的jar包及目錄中class
4)Custom ClassLoader
屬於應用程式根據自身需要自訂的ClassLoader,如tomcat、jboss都會根據j2ee規範自行實現ClassLoader
載入過程中會先檢查類是否被已載入,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查,
只要某個classloader已載入就視為已載入此類,保證此類只所有ClassLoader載入一次。而載入的順序是自頂向下,也就是由上層來逐層嘗試載入此類。
本文出自:http://www.cnblogs.com/javaee6/p/3714716.html http://m.blog.csdn.net/gjanyanlig/article/details/6818655
java類載入詳解