本文來自http://blog.csdn.net/liuxian13183/ ,援用必須注明出處!
前兩節我們探討了Java類內存模塊,文件結構,和Jvm的回收機制,今天我們再來探討1下它的文件加載機制,都知道Jvm要加載的是2進制流,可以是.class文件情勢,也能夠是其他情勢,總之依照它加載的標準來設計就不會有太大問題,以下主要就機制和標準兩個問題分析1番
首先來講Java類文件的加載機制,跟變量的加載機制類似,它先把Class文件加載入內存,再對數據進行驗證、解析和初始化,終究構成虛擬機可以直接使用的Java類型。由于Java是采取JIT機制,所以加載時會比較慢,但優點也明顯,具有高度靈活性,支持動態加載和動態連接。接下來就講講類的加載進程:
1個類加載的基本進程是依照下面的順序來,但也有不嚴格依照這個順序來的,也有打亂順序來的,如動態加載就得先初始化再解析。
1、加載- 由虛擬機自行決定,但也有由于下面的階段要履行而履行上面階段的情況。這時候虛擬機會做3件事,第1、通過全限定名讀取文件的2進制流,第2、把文件里的靜態方法和變量放到方法區中,第3、生成1個對象放入堆中,作為訪問入口。注意第1條,僅是讀取2進制流,沒說具體從甚么文件中讀,也沒說從哪里讀,所以造就Java很強的擴大性,可以從Jar、Zip中,也能夠從網絡層、數據庫層等 。主要是對象和方法區的聲明。
2、驗證 確保2進制流符合虛擬機的要求,不符合會報VerifyError。 第1、文件格式驗證,是不是有魔數,是不是符合Java文件的要求,詳見:Java高級之類結構的認識;第2、元數據驗證,是不是符合Java代碼規范,如abstract類是不是直接被實例化,普通類有沒有間接或直接父類Object等;第3、字節碼驗證,對數據流和控制流進行分析,保證不會做出危害虛擬機的行動,如是不是調用不存在的指令,是不是把父類賦值給子類,是不是把對象賦值給1個非此類型的對象等;第4、符號援用驗證,主要是類、變量、方法描寫是不是能找的到,如全限定名是不是能找到該文件,是不是具有可訪問性等。主要對內部結構的判定
3、準備 為類變量賦初值,通常為0值如靜態變量,而不會為實例變量賦值。
4、解析 將常量池中的符號援用轉化為直接援用的進程。這里說的符號援用指變量類型,直接援用指可以直接定位到對象的句柄。類、方法、字段、接口解析,根據全限定名取得相干對象,拿到它的類型,若無對所在類訪問權會拋出IllegalAccessError,無字段NoSuchFieldError,無方法NoSuchMethodError,是類不是接口會拋出IncompatibleClassChangeError
5、初始化 根據程序要求加載類和必要的資源。有且唯一4種情況,需要主動初始化后才能履行接下來的操作 ,所以要先履行上面的4步。第1、有new或static關鍵字的類,new生成對象,static靜態加載,這兩個很明顯要履行初始化了;第2、使用類有父類,這沒辦法了;第3、反射類里的方法,那肯定要初始化了對不對;第4、履行的主類,用main方法的類。其他被動初始化的情況不需要斟酌。
小例子:
這個時候加載類構造器<clinit>,會初始化類中所有變量,固然父類先于子類初始化
6、使用 加載完以后,該怎樣樣調用怎樣樣調用,繪圖啊,計算啊等等
7、卸載 類不再被調用
兩個類是不是相等,主要在于第1使用同1個加載器加載,第2全限定名地址1致
為何要提出上面的問題呢?接下來要講講虛擬機的1個加載機制。
在虛擬機的角度來看,有兩種類加載器,1種叫系統加載器(Bootstrap ClassLoader),1種叫自定義加載器(extends ClassLoader),這類呢又分為兩個,1種叫利用加載器,1種叫擴大類加載器,1般默許為前者;而我們的利用程序加載主要由上面3個加載器相互配合完成的。3者的關系如Application-->Extension-->Bootsrap,雙親委派機制是指兩兩以組合的方式,子加載器先去調用父加載器的方法,沒找到目標對象再去用子加載器
偽代碼以下:
loadClass(String name,boolean resolve){
Class c=findLoadedClass()
if(c==null){
try{
if(parent !=null)
c=parent.loadClass(name,false);
else
c=findBootstrapClassOrNull(name);
}catch(ClassNotFoundException e){ }
}
if(c==null)
c=findClass(name);
}
Java提倡我們去把自己調用類的邏輯寫在findClass里,這樣有助于雙親委派機制的正常使用。
破壞1、重寫loadClass
破壞2、使用線程上下文加載器去讓父加載器去調用子加載器的方法
破壞3、熱加載 現在經常使用的做法是自定義類加載器并將原bug模塊覆蓋-OSGI
但由于自定義加載器之間的規則如果混亂,出現同時相互援用的問題,那末會終究找不到類,而出現線程死鎖和內存泄漏的問題。
下1節我們會討論1下線程并發的問題。