AssetBundle使用,卸載,校驗(yàn)
928
2025-04-03
一、類的加載時機(jī)
我們通過javac將Java文件編譯成的.class文件什么時候會被加載到JVM中?
在虛擬機(jī)規(guī)范中嚴(yán)格定義了有且只有五種情況必須立即對類進(jìn)行初始化(也就是將class文件加載到JVM中):
創(chuàng)建類的實(shí)例(new的方式)。訪問某個類或接口的靜態(tài)變量,或者對該靜態(tài)變量進(jìn)行賦值,調(diào)用類的靜態(tài)方法等
反射的方式
初始化某個類的子類,則其父類也會被初始化
Java虛擬機(jī)啟動的時候被標(biāo)明為啟動類的類,直接使用java.exe命令來運(yùn)行某個主類(包括main方法的那個類)
當(dāng)使用JDK1.7的動態(tài)類型 語言支持(java.lang.invoke包下)時
所以說java類的加載是動態(tài)的,它并不是一次性將所有類全部加載后再運(yùn)行,而是保留程序運(yùn)行的基礎(chǔ)類(也就是基類)完全加載到j(luò)vm中,至于其他類,則在需要的時候才加載,這就是為了節(jié)省內(nèi)存開銷。
二、如何將類加載到j(luò)vm中
class文件是通過類加載器加載到j(luò)vm中的。
那么java默認(rèn)有三種類型的加載器:應(yīng)用類、拓展類和引導(dǎo)類加載器
各個加載器的工作職責(zé):
啟動類加載器:負(fù)責(zé)加載$JAVA_HOME中jre/lib/rt.jar里面的所有class,由C++實(shí)現(xiàn),不是ClassLoader子類
拓展類加載器:負(fù)責(zé)加載Java平臺中拓展功能的一些jar包,包括$JAVA_HOME中jre/lib/ext/*.jar或-Djava.ext.dirs指定目錄下的jar包
應(yīng)用類加載器:負(fù)責(zé)加載classpath中指定的jar包及目錄中class
類加載器工作過程:
當(dāng)應(yīng)用類加載器加載一個class的時候,它首先自己不會嘗試加載這個類,而是把class請求委派給父類加載器-拓展類加載器去完成。
當(dāng)拓展類加載器加載一個class的時候,它首先也不會自己去加載這個class,而是把這個class委派給引導(dǎo)類加載器。
如果引導(dǎo)類加載器加載class失敗(例如在$JAVA_HOME/jre/lib里面未找到該class),會使用拓展類加載器來嘗試加載。
如果拓展類加載器也加載失敗,則會使用引導(dǎo)類加載器來加載。
如果引導(dǎo)類也加載失敗,則會報ClassNotFoundException異常
上面的工作過程其實(shí)就是雙親委派模型,如果一個類加載器加收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把類加載這個請求委托給父類加載器去完成,一次向上。這樣可以防止內(nèi)存中出現(xiàn)多份同樣的字節(jié)碼(安全性角度)。
類加載器在加載成功這個類之后,會把得到的java.lang.class類實(shí)例緩存起來,下次再請請求加載該類的時候,類加載器會直接使用緩存的類實(shí)例了,而不會嘗試再次加載。
類加載到JVM中詳細(xì)過程
加載,查找并加載類的.class字節(jié)碼二進(jìn)制數(shù)據(jù),同時在java堆中創(chuàng)建一個java.lang.Class類的對象(該對象在編譯期就存在.class文件中,一個類的實(shí)例對象只能對應(yīng)一個Class對象,所以在共享堆中創(chuàng)建一份)。
連接,分為三塊內(nèi)容:驗(yàn)證、準(zhǔn)備、解析。
驗(yàn)證,包括文件格式、元數(shù)據(jù)、字節(jié)碼和符號引用等驗(yàn)證
準(zhǔn)備,為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認(rèn)值
解析,把類中的符號引用轉(zhuǎn)換為直接引用
初始化,為類的靜態(tài)變量賦予正確的初始值
類編譯優(yōu)化-JIT即時編譯器
在JVM加載這些class文件之后,對這些字節(jié)碼如果是逐條取出,逐條執(zhí)行(解析器解析)的話,會很慢,JVM會做進(jìn)一步的優(yōu)化:
拿到這些字節(jié)碼之后,會對這些Java字節(jié)碼進(jìn)行重新編譯優(yōu)化,生成機(jī)器碼,讓CPU直接執(zhí)行,這樣編譯出來的代理效率更高,但重新編譯也是需要時間的,所以JVM會對熱點(diǎn)代碼做重新編譯,而非熱點(diǎn)代碼就直接解析好了,重新編譯熱點(diǎn)代碼就使用JIT即時編譯期來實(shí)現(xiàn)。
那么檢測是否為熱點(diǎn)代碼的方式有:采樣和計數(shù)器。
HotSpot VM使用的是計數(shù)器的方法檢測熱點(diǎn)代碼,其具體實(shí)現(xiàn)是通過兩個計數(shù)器:方法調(diào)用計數(shù)器和回邊計數(shù)器;在確定虛擬機(jī)運(yùn)行參數(shù)的前提下,這兩個計數(shù)器都有一個閾值,當(dāng)計數(shù)器超過閾值溢出了,就會觸發(fā)JIT編譯。
三、總結(jié)-一個對象的加載過程
一個.java文件經(jīng)過javac命令編譯成功后,會得到一個.class字節(jié)碼文件
當(dāng)我們執(zhí)行了初始化操作(上面五種情況:new操作、子類初始化【父類也會一同初始化】,反射等等),會將讀取.class字節(jié)碼文件,取出二進(jìn)制數(shù)據(jù),通過類加載器裝載到j(luò)vm內(nèi)存中
將.class文件加載到j(luò)vm中需要經(jīng)過加載,連接(驗(yàn)證、準(zhǔn)備、解析class文件信息)和初始化。
在加載的時候,會在Java堆中創(chuàng)建生成一個java.lang.class類的對象,這個Class對象代表著類相關(guān)的信息,只要是類有什么東西(包括成員變量,方法和構(gòu)造器等該Class對象都有對應(yīng)的方法getFields(),getMethods(),getConstructors()),在Class對象中都可以找得到,然后就可以使用Class對象創(chuàng)建類的具體實(shí)例來進(jìn)行調(diào)用實(shí)現(xiàn)的具體功能,我們還可以通過Class對象來判斷對象的真正類型
jvm還會對熱點(diǎn)代碼進(jìn)行重新編譯優(yōu)化,使用JIT編譯技術(shù)進(jìn)行優(yōu)化,提高運(yùn)行效率
Java JVM
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。