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































