柚子快報激活碼778899分享:java jvm類加載機制概述
柚子快報激活碼778899分享:java jvm類加載機制概述
、什么是jvm的類加載機制
?
類加載機制是指我們將類的字節(jié)碼文件所包含的數(shù)據(jù)讀入內(nèi)存,同時我們會生成數(shù)據(jù)的訪問入口的一種 特殊機制。那么我們可以得知,類加載的最終產(chǎn)品是數(shù)據(jù)訪問入口。
?
加載類文件(即.class文件)的方式有以下幾種:
?
從本地系統(tǒng)中直接加載。
通過網(wǎng)絡(luò)下載的.class文件。比如Web Applet,也就是我們的小程序應(yīng)用。
從war,jar等歸檔文件中加載class。
從專有數(shù)據(jù)庫中提取.class文件。
將java源文件動態(tài)編譯為.class文件,也就是運行時計算而成,java的動態(tài)代理技術(shù)就是這么實現(xiàn)的。
從加密文件中獲取。典型的防止class文件被反編譯的保護措施。
回到頂部
2、類裝載的過程
類從被加載到虛擬機內(nèi)存中開始,到卸載出內(nèi)存為止,它的整個過程包括:裝載、驗證、準(zhǔn)備、解析、初始化、使用、卸載7個階段。其中驗證、準(zhǔn)備、解析統(tǒng)稱為鏈接。如下圖 ? ?
?
?
?
?
?
裝載(Loading):
通過一個類的全限定名獲取定義此類的二進制字節(jié)流,由上文可知,我們不一定從字節(jié)碼文件中獲取字節(jié)流,還能通過上述多種方式獲取字節(jié)流。
將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)。
在java堆中生存一個代表這個類的java.lang.Class對象,作為對方法區(qū)中這些數(shù)據(jù)的訪問入庫。?
獲取類的二進制字節(jié)流的階段是我們java程序員最關(guān)注的階段,也是操作性最強的一個階段,因為這個階段我們可以對我們的類加載器進行操作 ,比如我們想自定義類加載器進行操作完成加載,又或者我們想通過java agent來完成我們的字節(jié)碼增強操作。
?
連接(Linking):
驗證(Verification):驗證主要是為了保證被加載類的正確性,即裝載的Class文件中的字節(jié)流保護的信息是否符合當(dāng)前虛擬機的要求,并且還要求我們的信息不會危害虛擬機自身的安全,導(dǎo)致虛擬機的崩潰。這其中包括四個階段:
文件格式的驗證:第一階段要驗證字節(jié)流是否符合class文件格式的規(guī)范,并且能被當(dāng)前版本的虛擬機處理
元數(shù)據(jù)的驗證:第二階段是對字節(jié)碼描述的信息進行語義分析,以保證其描述的信息符合Java語言規(guī)范的要求。
字節(jié)碼驗證:第三階段是整個驗證過程中最復(fù)雜的一個階段,主要目的是通過數(shù)據(jù)流和控制流分析,確定程序語義是合法的、符合邏輯的。在第二階段對元數(shù)據(jù)信息中的數(shù)據(jù)做完校驗后,這個階段將對類對方法體進行校驗分析,保證被校驗類對方法在運行時不會做出危害虛擬機安全對事件。
符號引用驗證:這是最后一個階段的驗證,它發(fā)生在虛擬機將符號引用轉(zhuǎn)化為直接引用的時候(解析階段), 可以看作是對類自身以外的信息(常量池中的各種符號引用)進行匹配性的校驗。符號引用 驗證的目的是確保解析動作能正常執(zhí)行。
準(zhǔn)備(Preparation):為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認(rèn)值。
解析(Resolution):
初始化(Initialization):
初始化階段是執(zhí)行類構(gòu)造器()方法的過程。在準(zhǔn)備階段,類變量已賦過一次系統(tǒng)要求對初始值,而在初始化階段,則是根據(jù)程序員通過程序制定的主觀計劃去初始化類變量和其他資源,比如賦值。
?
在java中,對于初始化階段,有且只有以下五種情況才會對要求類立刻“初始化”(加載,驗證,準(zhǔn)備,自然需要在此之前開始):
?
使用new關(guān)鍵字實例化對象、訪問或者設(shè)置一個類的靜態(tài)字段(被final修飾、編譯器優(yōu)化時已經(jīng)放入常量池的例外)、調(diào)用類方法,都會初始化該靜態(tài)字段或者靜態(tài)方法所在的類。
初始化類的時候,如果其父類沒有被初始化過,則要先觸發(fā)其父類初始化。
使用java.lang.reflect包的方法進行反射調(diào)用的時候,如果類沒有被初始化,則要先初始化。
虛擬機啟動時,用戶會先初始化要執(zhí)行的主類(含有main)
jdk 1.7后,如果java.lang.invoke.MethodHandle的實例最后對應(yīng)的解析結(jié)果是 REF_getStatic、REF_putStatic、REF_invokeStatic方法句柄,并且這個方法所在類沒有初始化,則先初始化。
使用(Useing):
主動使用:
創(chuàng)建類的實例,也就是new的方式
訪問某個類或接口的靜態(tài)變量,或者對該靜態(tài)變量賦值
調(diào)用類的靜態(tài)方法
反射
初始化某個類的子類,則其父類也會進行初始化
java虛擬機啟動時被標(biāo)明為啟動類的類(SpringbootApplication類)
被動使用:
引用父類的靜態(tài)字段,只會引起父類的初始化,而不會引起子類的初始化
定義類數(shù)組,不會引起類的初始化
引用類的static final常量,不會引起類的初始化(如果只有static修飾,還是會引起該類初始化 的)
?
卸載(Unloading):
在類使用完成之后,如果滿足下面的情況,類就會被卸載:
?
該類所有的實例都已經(jīng)被回收,也就是java堆中不存在該類的任何實例
加載該類的ClassLoader已經(jīng)被回收
該類對應(yīng)的java.lang.Class對象沒有任何地方被引用,無法在任何地方通過反射訪問該類的方法?
?
如果以上三個條件全部滿足,jvm就會在方法區(qū)垃圾回收的時候?qū)︻愡M行卸載,類對卸載過程其實就是在方法區(qū)中清空類信息,java類對整個生命周期就結(jié)束類。但是一般情況下啟動類加載器加載的類不會被卸載,而我們的其他兩種基礎(chǔ)類型的類加載器只有極少的情況下才會被卸載。
?
回到頂部
3、類的加載器
java的類記載器是負(fù)責(zé)讀取java字節(jié)碼,并轉(zhuǎn)換成java.lang.class類的一個實例的代碼模塊。類加載器除了用于加載類外,還可以用于確定類在java虛擬機的唯一性?! ?/p>
?
? ? ? 一個類在同一個類加載器中具有唯一性(Uniqueness),而不同類加載器中是允許同名類存在的, 這里的同名是指全限定名相同。但是在整個JVM里,縱然全限定名相同,若類加載器不同,則仍 然不算作是同一個類,無法通過 instanceOf 、equals 等方式的校驗。
?
java虛擬機自帶有以下三種類加載器:
?
Bootstrap ClassLoader
負(fù)責(zé)加載$JAVA_HOME中 jre/lib/rt.jar 里所有的class或Xbootclassoath選項指定的jar包。由 C++實現(xiàn),不是ClassLoader子類。
Extension ClassLoader
負(fù)責(zé)加載java平臺中擴展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar 或 -Djava.ext.dirs 指定目錄下的jar包。
Application ClassLoader
負(fù)責(zé)加載classpath中指定的jar包及 Djava.class.path 所指定目錄下的類和jar包。
?
?
除此之外,用戶也可以自定義類加載器:
?
User ClassLoad
通過java.lang.ClassLoader的子類自定義加載class,屬于應(yīng)用程序根據(jù)自身需要自定義的 ClassLoader,如tomcat、jboss都會根據(jù)j2ee規(guī)范自行實現(xiàn)ClassLoader。
?
?
?
?
回到頂部
4、雙親委派機制
“雙親委派”是指子類加載器如果沒有加載過該目標(biāo)類,就先委托父類加載器加載該目標(biāo) 類,只有在父類加載器找不到字節(jié)碼文件的情況下才從自己的類路徑中查找并裝載目標(biāo)類。
?
?
“雙親委派”機制加載Class的具體過程是:
?
ClassLoader先判斷該Class是否已加載,如果已加載,則返回Class對象;如果沒有則委托 給父類加載器。
?
父類加載器判斷是否加載過該Class,如果已加載,則返回Class對象;如果沒有則委托給祖 父類加載器。
?
依此類推,直到始祖類加載器(引用類加載器)。
?
始祖類加載器判斷是否加載過該Class,如果已加載,則返回Class對象;如果沒有則嘗試從其對應(yīng)的類路徑下尋找class字節(jié)碼文件并載入。如果載入成功,則返回Class對象;如果載入失敗,則委托給始祖類加載器的子類加載器。
?
始祖類加載器的子類加載器嘗試從其對應(yīng)的類路徑下尋找class字節(jié)碼文件并載入。如果載入成功,則返回Class對象;如果載入失敗,則委托給始祖類加載器的孫類加載器。
?
依此類推,直到源ClassLoader。
?
源ClassLoader嘗試從其對應(yīng)的類路徑下尋找class字節(jié)碼文件并載入。如果載入成功,則返回Class對象;如果載入失敗,源ClassLoader不會再委托其子類加載器,而是拋出異常。
?
?
?
?
?
?
“雙親委派”機制只是Java推薦的機制,并不是強制的機制。我們可以繼承java.lang.ClassLoader類,實現(xiàn)自己的類加載器。如果想保持雙親委派模型,就應(yīng) 該重寫findClass(name)方法;如果想破壞雙親委派模型,可以重寫loadClass(name)方法。
?
柚子快報激活碼778899分享:java jvm類加載機制概述
推薦閱讀
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。