JVM加載過程及異常
1、虛擬機執(zhí)行過程
虛擬機(jvm)把描述類的數(shù)據(jù)從class文件或其他形式數(shù)據(jù)加載到內(nèi)存,并對數(shù)據(jù)進行校驗、準備、解析和初始化。最終形成可以被虛擬機直接使用的Java 類型。這就是虛擬機的類加載機制。
類加載的生命周期包括:加載、鏈接(驗證、準備和解析)、初始化、使用、卸載。
啟 動
Jvm通過調(diào)用某個類指定類的main方法啟動,傳遞給main所在類一個字符串數(shù)組。如下:
java Test hello smurfs, welcome to jvm.這樣jvm通過加載Test.class文件,然后把hello smurfs, welcome to jvm.作為5個長度的字符串數(shù)據(jù)傳遞給Test類的main方法去執(zhí)行。
Jvm加載Test.class文件后,通過鏈接步驟,把Test.class生成的class對象鏈接到對應的類型,然后進行初始化操作,在所有都正確完成之后,才構造了一個完整的Test類對象,進而才能正確的執(zhí)行方法。
⑴class文件裝載:尋找一個具有特定名稱的類的二進制形式,并且用這個二進制形式構造一個代表該類的class對象的過程叫裝載(是個動詞,指過程)。裝載是通過ClassLoader和其子類實現(xiàn)的,ClassLoader的不同子類可以實現(xiàn)不同的裝載策略,包括class文件加密()、特殊位置加載(網(wǎng)絡加載)等都是通過classloader來完成的。類加載后的信息存在于jvm的方法區(qū)域內(nèi),這個區(qū)域緩存這類的信息,并且這個區(qū)域基本是不進行垃圾回收的,因此如果沒有進行classloader加載對象的清空,新的class文件替代舊class文件后,類信息并沒有被替換。
在加載階段,虛擬機需要完成以下3件事情:
1、通過類的全限定名來獲取定義此類的二進制流;
2、將這個二進制流所代表的靜態(tài)存儲結構轉(zhuǎn)化為方法區(qū)(jvm內(nèi)存)的運行時數(shù)據(jù)
3、在Java 堆(jvm內(nèi)存)中生成一個代表類的java.lang.Class對象,作為方法區(qū)這些數(shù)據(jù)的入口。
如果類的裝載出現(xiàn)錯誤,會拋出LinkageError異常的以下3個子類示例:
lClassCircularityError:因一個類或接口是自身的超類而不能被加載。
lClassFormatError:所要求的編譯后的類的二進制數(shù)據(jù)是損壞的。
lNoClassDefFoundError:找不到類的定義。
以上3中error,以下一一舉例:
l在不包含Test.java的目錄里執(zhí)行java Test后出現(xiàn)NoClassDefFoundError
l接下來看看ClassFormatError錯誤,首先編寫個Test.java文件,內(nèi)容如下:
修改編譯后Test.class文件,把其中的println改成printl后,再通過java Test執(zhí)行:
l最后來看ClassCircularityError錯誤。正常清空下,這種錯誤是不會存在的,但是當大型項目,需要很多人提交代碼時就可能會出現(xiàn)問題。
首先編寫2個類,Test和A,Test繼承與A,詳細代碼如下:
編譯后產(chǎn)生Test.class和A.class 2個2進制文件,刪除A.class,把Test.class改名保護起來為Test.class.a,再編寫Test和A,這次A繼承自Test,詳細代碼如下:
這次編譯后刪除Test.class,保留A.class文件,然后把先前改名的Test.class.a該回Test.class,再執(zhí)行java Test后
從二進制源碼看,實際上Test繼承了自身,因此會有如此的error。
原文鏈接:http://smurfs.iteye.com/blog/1433142
【編輯推薦】