您好,登錄后才能下訂單哦!
這篇文章主要講解了“JVM分析之類加載機(jī)制是什么”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“JVM分析之類加載機(jī)制是什么”吧!
JVM內(nèi)部架構(gòu)包含類加載器、內(nèi)存區(qū)域、執(zhí)行引擎等。日常開發(fā)中,我們編寫的java文件被編譯成class文件后,jvm會進(jìn)行加載并運(yùn)行使用類。本次僅對JVM加載部分進(jìn)行分析,了解并掌握加載機(jī)制。
類加載是一種過程,是將class文件加載到j(luò)vm內(nèi)存的過程。當(dāng)代碼邏輯中需要引用類時,通過類加載器加載引用類對象并存放堆中,以供代碼調(diào)用。
注:類加載過程包含 加載、鏈接(驗(yàn)證、準(zhǔn)備、解析)、初始化
加載:將類的class字節(jié)碼文件讀到內(nèi)存,將其存放到運(yùn)行時數(shù)據(jù)區(qū)的方法區(qū),然后在堆區(qū)生成class對象,封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)。(方法區(qū)-》數(shù)據(jù)結(jié)構(gòu),堆區(qū)-》class對象)
過程:java文件-》通過java c編譯成字節(jié)碼.class文件-》引導(dǎo)類加載器(裝載核心類庫)-》擴(kuò)展類加載器(將指定目錄jar包裝載至工作庫)-》系統(tǒng)類加載器(將指定目錄的類和jar包裝載至工作庫,常用)-》自定義類加載器(實(shí)現(xiàn)加載指定類或自定義加密等操作)
緩存:類加載到j(luò)vm后,會緩存一段時間(不管是否被引用),待jvm執(zhí)行垃圾回收時才會回收未使用的緩存類,釋放空間。
類加載器:
啟動類加載器:Bootstrap ClassLoader由C/C++實(shí)現(xiàn),嵌套在JVM中,java程序無法直接操作;負(fù)責(zé)加載Java核心類庫($JAVA_HOME中jre/lib目錄下或-Xbootclasspath參數(shù)指定的路徑目錄下,如java.*開頭的類)的class文件。
擴(kuò)展類加載器:Extension ClassLoader由Java編寫,由sun.misc.Launcher$ExtClassLoader
實(shí)現(xiàn)。加載java平臺擴(kuò)展的jar包,負(fù)責(zé)加載(java.ext.dirs目錄或$JAVA_HOME
中jre/lib/ext
目錄,如javax.開頭的類)的class文件。
應(yīng)用程序類加載器:Application ClassLoader由Java編寫,由sun.misc.Launcher$AppClassLoader
實(shí)現(xiàn)。負(fù)責(zé)加載用戶類路徑(classpath)的class文件,java程序一般默認(rèn)使用應(yīng)用程序類加載器。
自定義類加載器:一般情況下java程序使用上面三種類加載器就滿足了,一些特殊情況下,我們需要自定義加載指定路徑的類時,就需要繼承java.lang.ClassLoader類,重寫find Class或loadClass均可實(shí)現(xiàn)。(類隔離實(shí)踐中就采用此方案)
類加載機(jī)制
全盤負(fù)責(zé):當(dāng)加載器加載某個class時,該class所引用的其他class也一并被加載(自定義加載class除外);
緩存機(jī)制:所有加載過的class均被緩存,當(dāng)程序中使用某個class時,優(yōu)先從緩存區(qū)中獲取,如果緩存區(qū)不存在,才會讀取該class的字節(jié)碼文件,加載為class對象,并存入緩存區(qū),以便后續(xù)使用。(修改class后,需要重啟jvm才會生效)
雙親委派:是一種類加載安全機(jī)制,當(dāng)類加載器需要加載某個class文件時,會優(yōu)先把加載委托給父類加載器處理,如果加載成功則返回,否則繼續(xù)向上委托直至最頂層類加載器,當(dāng)父類加載器在加載范圍內(nèi)均沒有找到所需class文件,即表示無法完成加載,此時子加載器才會去加載。(先向上委托父類加載器處理,都失敗后在自己再加載)
反向委派:主要是用于第三方包加載,第三方包的類不在jdk/lib目錄,所以Bootstrap ClassLoader引導(dǎo)類加載器無法直接加載SPI(Service Provider Interface,服務(wù)提供者接口)的實(shí)現(xiàn)類,雙親委派機(jī)制中定義無法反向委托Application Classloader系統(tǒng)加載器加載,因此需要一種特殊的ContextClassLoader線程上下文類加載器來加載第三方的類庫。(*** 此處SPI接口后續(xù)文章分析 ***)
加載實(shí)現(xiàn)方式
/* * 類加載方式 * 1、類加載器,此方式加載的class對象還沒有完成鏈接階段 * 2、java.lang.Class,此方式加載的class對象是完成初始化的 * */ ClassLoader classLoader = ClassSegregationTest.class.getClassLoader(); classLoader.loadClass("com.lgy.example.class_segregation.SegregationTestA"); // 默認(rèn)初始化class對象 Class.forName("com.lgy.example.class_segregation.SegregationTestA"); // 默認(rèn)不初始化,并且指定類加載器進(jìn)行加載 Class.forName("com.lgy.example.class_segregation.SegregationTestA", false, classLoader);
鏈接是將java二進(jìn)制代碼合并至jvm運(yùn)行的過程。
鏈接過程可分為 驗(yàn)證、準(zhǔn)備、解析 三個階段。
驗(yàn)證
保證正確加載類,包括文件格式驗(yàn)證(Class文件格式的規(guī)范)、元數(shù)據(jù)驗(yàn)證(Java語言規(guī)范)、字節(jié)碼驗(yàn)證(通過數(shù)據(jù)流和控制流分析)、符號引用驗(yàn)證。
準(zhǔn)備
在方法區(qū)為靜態(tài)變量(static修飾)分配內(nèi)存,并設(shè)置類變量初始值(通常是數(shù)據(jù)類型默認(rèn)的零值,如0,0L,null,false等)。
顯示賦值是在類對象實(shí)例化時處理(即 public static int x=10,準(zhǔn)備階段初始值為0,在對象實(shí)例化時,才被賦值10)
解析
虛擬機(jī)中將常量池的符號引用(常量名)替換為直接引用(目標(biāo)的指針地址)的過程;
符號引用的目標(biāo)不一定在內(nèi)存中,但常量名(或稱字面量)是明確定義在jvm規(guī)范的class文件格式中。
直接引用是指向目標(biāo)的指針地址、相對偏移量或間接定位到目標(biāo)的句柄,是肯定在內(nèi)存中。
執(zhí)行每個類的構(gòu)造方法init()的過程,init()方法是java編譯器自動收集、合并所有類變量的賦值動作和靜態(tài)代碼塊語句,完成初始化。
初始化步驟
類未被加載或鏈接,則程序先加載并鏈接該類
優(yōu)先初始化直接父類,再執(zhí)行子類初始化
依次執(zhí)行類中的初始化語句
初始化條件(只有對類主動使用時才會初始化類)
創(chuàng)建類實(shí)例(new Class)
類或接口靜態(tài)變量的引用或賦值
類靜態(tài)方法的調(diào)用
反射加載(Class.forName(''))
子類被初始化,其父類也會被初始化
jvm啟動時被標(biāo)記啟動類的類,或直接java.exe命令運(yùn)行指定類
演示代碼如下:
/** * 定義父類與子類 */ class Parent { public static int a = 10; static { System.out.println(" 父類初始化 "); } } class Children extends Parent{ public static int a = 100; static { System.out.println(" 子類初始化 "); } } public static void main(String[] args) throws Exception { // 子類沒有定義變量a ( public static int a = 100;) System.out.println(Children.a); // 輸出 -- 父類初始化 -- 10 // 主動調(diào)用時才會執(zhí)行類的靜態(tài)塊 ----------------------------------------- // 子類定義變量a System.out.println(Children.a); // 輸出 -- 父類初始化 -- 子類初始化 -- 100 // 子類被初始化時,優(yōu)先初始化父類,所以父類靜態(tài)塊執(zhí)行;調(diào)用變量a屬于子類定義,屬于主動調(diào)用,所以子類靜態(tài)塊執(zhí)行 }
調(diào)試輸出加載對象(VM options 中添加 -XX:+TraceClassLoading)
[Loaded com.lgy.example.class_segregation.Parent from file:/E:/dataway-demo/example/target/classes/]
[Loaded com.lgy.example.class_segregation.Children from file:/E:/dataway-demo/example/target/classes/]
僅在首次主動使用才會被初始化。
感謝各位的閱讀,以上就是“JVM分析之類加載機(jī)制是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對JVM分析之類加載機(jī)制是什么這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。