Java虛擬機(jī)——類加載機(jī)制和類加載器
類加載過程
類從被加載到虛擬機(jī)內(nèi)存中開始,到卸載出內(nèi)存為止分瘾,它的整個(gè)生命周期包括:Loading(加載)德召、Verification(驗(yàn)證)、Preparation(準(zhǔn)備)福荸、Resolution(解析)肴掷、Initialization(初始化)、Using(使用)和Unloading(卸載)7個(gè)階段台夺。其中驗(yàn)證痴脾、準(zhǔn)備、解析3個(gè)部分統(tǒng)稱為連接(Linking)
注意:此處的類加載指的是一個(gè).class文件的加載滚朵,在Java中.class文件可能是一個(gè)類辕近,也可能是一個(gè)接口匿垄。此處都叫做類加載。整個(gè)類加載的過程即:加載→驗(yàn)證→準(zhǔn)備→解析→初始化吞杭。
這里需要注意:從類的加載→驗(yàn)證→準(zhǔn)備→初始化变丧,過程是按順序依次開始的,但是解析比較特殊童擎。為了支持java語言的晚期綁定/動態(tài)綁定攻晒,有時(shí)解析可以在初始化之后才開始。而且芯砸,這只是開始順序假丧,一個(gè)階段通常執(zhí)行的過程中會激活調(diào)用另一個(gè)階段,所以各個(gè)階段只是按照這個(gè)順序開始渔期,而不會等一個(gè)階段完全完成后才進(jìn)行下一個(gè)階段渴邦,各個(gè)階段是交叉混合進(jìn)行的,所以各階段并不會嚴(yán)格按照此順序結(jié)束谋梭。
1.Loading加載
在加載階段章蚣,虛擬機(jī)需要完成以下3件事情:
1)通過一個(gè)類的全限定名來獲取此類的二進(jìn)制字節(jié)流。
一個(gè)類的二進(jìn)制字節(jié)流即.class文件矾策,如何獲取一個(gè)類的.class文件其實(shí)可以通過多種方法實(shí)現(xiàn)峭沦,譬如:從ZIP包中讀取、從網(wǎng)絡(luò)傳輸中獲取蓬豁、運(yùn)行時(shí)計(jì)算生成(動態(tài)代理技術(shù))菇肃、從數(shù)據(jù)庫中讀取等琐谤。
2)將這個(gè)字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)。
加載的過程中主要由【類加載器】來完成质礼。類加載器也分為不同種類,具體見下文↓织阳,除了JVM自帶的類加載器眶蕉,用戶也可以使用自己定義的類加載器。
3)在內(nèi)存中生成一個(gè)代表這個(gè)類的java.lang.Class對象,作為方法區(qū)這個(gè)類的各種數(shù)據(jù)的訪問入口唧躲。
某個(gè)類的java.lang.Class對象造挽,即通常所說的一個(gè)類的類對象碱璃,這個(gè)類對象作為程序調(diào)用這個(gè)類中方法和數(shù)據(jù)調(diào)用的入口。類對象生成的方式主要有以下5種:1). 使用new關(guān)鍵字創(chuàng)建對象2). 使用Class類的newInstance方法(反射機(jī)制)3). 使用Constructor類的newInstance方法(反射機(jī)制)4). 使用Clone方法創(chuàng)建對象5). 使用(反)序列化機(jī)制創(chuàng)建對象刽宪。具體可以看這篇文章:
https://blog.csdn.net/justloveyou_/article/details/72466416
2.Verification驗(yàn)證
驗(yàn)證是連接階段的第一步厘贼,這一階段的主要目的是為了確保Class文件的字節(jié)流包含的信息符合當(dāng)前虛擬機(jī)的要求界酒,并且不會危害虛擬機(jī)自身的安全圣拄。驗(yàn)證階段是非常重要的毁欣,這個(gè)階段是否嚴(yán)謹(jǐn)庇谆,直接決定了Java虛擬機(jī)是否能夠承受惡意代碼的攻擊,從執(zhí)行性能的角度上講凭疮,驗(yàn)證階段的工作量在虛擬機(jī)的類加載子系統(tǒng)中又占據(jù)了相當(dāng)大的一部分饭耳。
此階段主要包含如下幾個(gè)部分的驗(yàn)證:
1.文件格式驗(yàn)證? 2.元數(shù)據(jù)驗(yàn)證? 3.字節(jié)碼驗(yàn)證? 4.符號引用驗(yàn)證
3.Preparation準(zhǔn)備
準(zhǔn)備階段是正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段,這些變量使用的內(nèi)存都將在方法區(qū)中進(jìn)行分配执解。(此處需注意的是寞肖,準(zhǔn)備階段是為類變量分配內(nèi)存并設(shè)置初始值而不是實(shí)例變量,類變量屬于class衰腌,實(shí)例變量屬于方法新蟆。實(shí)例變量將會在對象實(shí)例化時(shí)隨著對象一起被分配在Java堆中)
4.Resolution解析
解析階段是虛擬機(jī)將常量池內(nèi)的符號引用替換為直接引用的過程。解析主要包括:
1.類或接口的解析 2.字段解析 3.類方法解析 4.接口方法解析
5.Initialization初始化
類初始化階段是類加載過程的最后一步右蕊,前面的類加載過程中琼稻,除了在加載階段用戶應(yīng)用程序可以通過自定義類加載器參與之外,其余動作完全由虛擬機(jī)主導(dǎo)和控制饶囚。到了初始化階段帕翻,才真正開始執(zhí)行類中定義的Java程序代碼(字節(jié)碼)。初始化對于類來說萝风,就是執(zhí)行類構(gòu)造器<clinit>()方法的過程嘀掸。
類加載器
類加載器的作用:
類加載器,顧名思義就是用來加載類的规惰,但是其作用不僅僅是加載類睬塌。因?yàn)閷τ谌我庖粋€(gè)類,都需要由加載它的類加載器和這個(gè)類本身一同確立其在Java虛擬機(jī)中的唯一性卿拴,每一個(gè)類加載器都擁有一個(gè)獨(dú)立的類名稱空間衫仑。
說直白點(diǎn):比較兩個(gè)類是否“相等”,只有它們是由同一個(gè)類加載器加載時(shí)堕花,才有意義文狱。對于同一個(gè)類,如果由不同類加載器加載缘挽,則他們也必然不相等瞄崇。
(相等包括Class對象的equals方法呻粹、isAssignableFrom()方法、isInstance()方法返回的結(jié)果,也包括用instanceof關(guān)鍵詞判斷的情況)
類加載器的分類:
A.從Java虛擬機(jī)的角度:
1.Bootstrap ClassLoader啟動類加載器
2.其他類加載器
從JVM的角度苏研,加載器只分為兩類,即JVM自身實(shí)現(xiàn)的Bootstrap啟動類加載器等浊,和其他JVM以外的所有類加載器。Bootstrap翻譯為根摹蘑,故也叫根類加載器筹燕。
B.從開發(fā)者的角度:
1.Bootstrap ClassLoader根類加載器
2.Extension ClassLoader拓展類加載器
3.Application ClassLoader應(yīng)用程序類加載器
1.根類加載器,加載位于/jre/lib目錄中的或者被參數(shù)-Xbootclasspath所指定的目錄下的核心Java類庫衅鹿。此類加載器是Java虛擬機(jī)的一部分撒踪,使用native代碼(C++)編寫。
如圖所示大渤,rt.jar這個(gè)jar包就是Bootstrap根類加載器負(fù)責(zé)加載的制妄,其中包含了java各種核心的類如java.lang,java.io,java.util,java.sql等
2.擴(kuò)展類加載器泵三,加載位于/jre/lib/ext目錄中的或者java.ext.dirs系統(tǒng)變量所指定的目錄下的拓展類庫耕捞。此加載器由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn)。
3.系統(tǒng)類加載器烫幕,加載用戶路徑(ClassPath)上所指定的類庫俺抽。此加載器由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn)。