溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JVM類加載

發(fā)布時間:2020-04-16 22:59:18 來源:網(wǎng)絡 閱讀:409 作者:xsster 欄目:開發(fā)技術

一、類加載器

1、什么是類加載器

類的加載指的是將類的.class文件中的二進制數(shù)據(jù)讀入到內(nèi)存中,將其放在運行時數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆區(qū)創(chuàng)建一個java.lang.Class對象,用來封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)。完成類加載的家伙就是類加載器。

2、都有哪些類加載器

JVM類加載

                    ClassLoader loader=Test01.         (loader!=              loader=loader.getParent();    }

結(jié)果:

  sun.misc.Launcher$AppClassLoader
  sun.misc.Launcher$ExtClassLoader
  null

JVM類加載

由輸出結(jié)果可以看出ExtClassLoader是AppClassLoader的父類,而ExtClassLoader的父類卻是null,原因是ExtClassLoader的父類加載器是BootStrap,BootStrap是JVM最底層的引導類加載器用C語言編寫的,所以找不到一個確定的返回父Loader的方式,于是就返回null。

為什么要有這個引導類加載器:

  類加載器也是java類,他們也需要類加載器加載進入內(nèi)存,顯然必須要有第一個不是java類的類加載器,來完成這個工作,這個正是BootStrap。

JVM中類加載器的結(jié)構(gòu):

JVM類加載

3、各個類加載器的作用

BootStrap  ClassLoader(啟動類加載器):負責加載存放在D:\Program Files (x86)\Java\jdk1.7.0_79\jre\lib下,或被-Xbootclasspath參數(shù)指定的路徑中的,并且能被虛擬機識別的類庫(如rt.jar,所有的java.*開頭的類均被Bootstrap ClassLoader加載)。啟動類加載器是無法被Java程序直接引用的。

Extension ClassLoader(擴展類加載器):該加載器由sun.misc.Launcher$ExtClassLoader實現(xiàn),它負責加載D:\Program Files (x86)\Java\jdk1.7.0_79\jre\lib\ext目錄中,或者由java.ext.dirs系統(tǒng)變量指定的路徑中的所有類庫(如javax.*開頭的類),開發(fā)者可以直接使用擴展類加載器。

Application ClassLoader(應用程序類加載器):該類加載器由sun.misc.Launcher$AppClassLoader來實現(xiàn),它負責加載用戶類路徑(ClassPath)所指定的類,開發(fā)者可以直接使用該類加載器,如果應用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認的類加載器。

4、JVM類加載機制(JVM需要加載一個類時,到底會派出哪個類加載器去執(zhí)行?)

全盤負責,當前線程的類加載器負責加載某個Class時,該Class所依賴的和引用的其他Class也將由該類加載器負責載入,除非顯示使用CLassLoader.loadClass()指定類加載器來載入

父類委托,先讓父類加載器試圖加載該類,只有在父類加載器無法加載該類時才嘗試從自己的類路徑中加載該類。所以我們在開發(fā)中盡量不要使用與JDK相同的類(例如自定義一個java.lang.System類),因為父類加載器中已經(jīng)有一份java.lang.System類了,它會直接將該類給程序使用,而你自定義的類壓根就不會被加載。

JVM類加載

123、如果BootStrap ClassLoader加載失?。ɡ缭?JAVA_HOME/jre/4、若ExtClassLoader也加載失敗,則會使用AppClassLoader來加載,如果AppClassLoader也加載失敗,則會報出異常ClassNotFoundException。

雙親委派模型意義:

  -系統(tǒng)類防止內(nèi)存中出現(xiàn)多份同樣的字節(jié)碼

  -保證Java程序安全穩(wěn)定運行

JVM類加載

緩存機制,緩存機制將會保證所有加載過的Class都會被緩存,當程序中需要使用某個Class時,類加載器先從緩存區(qū)尋找該Class,只有緩存區(qū)不存在,系統(tǒng)才會讀取該類對應的二進制數(shù)據(jù),并將其轉(zhuǎn)換成Class對象,存入緩存區(qū)。這就是為什么修改了Class后,必須重啟JVM,程序的修改才會生效。

5、自定義類加載器

 二、類的加載

1、類的加載:

  類的加載指的是將類的.class文件中的二進制數(shù)據(jù)讀入到內(nèi)存中,將其放在運行時數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆區(qū)創(chuàng)建一個java.lang.Class對象,用來封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)。類的加載的最終產(chǎn)品是位于堆區(qū)中的Class對象,Class對象封裝了類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu),并且向Java程序員提供了訪問方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)的接口。

JVM類加載

字節(jié)碼(.class)文件來源:

– 從本地系統(tǒng)中直接加載
– 通過網(wǎng)絡下載.class文件
– 從zip,jar等歸檔文件中加載.class文件 
– 從專有數(shù)據(jù)庫中提取.class文件
– 將Java源文件動態(tài)編譯為.class文件

 

2、類加載的過程

JVM將javac編譯好的class文件加載到內(nèi)存中,并對該數(shù)據(jù)進行驗證、解析和初始化,最終形成JVM可以直接使用的JAVA類型的過程。

JVM類加載

 

(1)、加載:加載階段其實就是JVM通過一個類的全限定名來獲取其定義的二進制字節(jié)流,并將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)且在Java堆中生成一個代表這個類的java.lang.Class對象,作為對方法區(qū)中這些數(shù)據(jù)的訪問入口。在該階段我們開發(fā)人員可以干預,例如:我們可以指定類加載器來加載該字節(jié)數(shù)組或者自定義類加載器來加載。

(2)、鏈接:將java類的二進制代碼合并到JVM的運行狀態(tài)中的過程

a、驗證:驗證是為了確保Class文件的字節(jié)流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。

b、準備:該階段是在方法區(qū)中為類變量(static變量)分配內(nèi)存并設置類變量初始值。例如:public static int flag=1;該階段初始化值為0。

c、解析:虛擬機將常量池中的符號引用替換為直接引用的過程。(直接引用就是直接指向目標的指針、相對偏移量或一個間接定位到目標的句柄)

(3)、初始化:初始化為類的靜態(tài)變量賦予正確的初始值,JVM負責對類進行初始化,主要對類變量進行初始化。

  • 初始化階段就是執(zhí)行類構(gòu)造器<clinit>()的過程,類構(gòu)造器<clinit>()是由編譯器自動收集類中的所有類變量的賦值動作和靜態(tài)語句塊中的語句合并產(chǎn)生的。

  • 當初始化一個類的時候,如果發(fā)現(xiàn)其父類還沒有進行過初始化,則需要先初始化其父類。

  • 虛擬機會保證一個類的<clinit>()方法在多線程環(huán)境中被正確加鎖和同步。

  • 當訪問一個java 類的靜態(tài)域時,只有正真申明這個域的類才會被初始化。

類的初始化時機:

  • 當虛擬機啟動則一定會加載main方法所在的類

JVM類加載

    width=100"靜態(tài)代碼塊"

JVM類加載

  • 當初始化一個類時,如果其父類未被初始化則一定先初始化其父類

JVM類加載

   = A "靜態(tài)代碼塊A""靜態(tài)代碼塊FatherA"

  靜態(tài)代碼塊FatherA
  靜態(tài)代碼塊A

JVM類加載

  • new一個對象的時候類被加載

  • 調(diào)用類的靜態(tài)方法和靜態(tài)成員變量(除了final常量 常量在編譯階段就存入調(diào)用類的常量池中,所以無需初始化類)

  • 使用java.lang.reflect包中的方法進行反射調(diào)用類會被初始化

類的被動引用不會初始化類:

  • 調(diào)用final常量不會初始化應為 常量在編譯階段就存入調(diào)用類的常量池中,所以無需初始化類。

  • 通過數(shù)組定義的類引用不會初始化類

JVM類加載

   = A[10"靜態(tài)代碼塊A"

JVM類加載

  • 當訪問一個靜態(tài)變量時,只有正真聲明這個靜態(tài)變量的類才會被初始化(通過子類調(diào)用父類的靜態(tài)變量,子類不會被初始化)

JVM類加載

    A "靜態(tài)代碼塊A"   width=100"靜態(tài)代碼塊FatherA"靜態(tài)代碼塊FatherA
 

JVM類加載

(4)、卸載

Java虛擬機將結(jié)束生命周期的時機:

  • 執(zhí)行了System.exit()方法

  • 程序正常執(zhí)行結(jié)束

  • 程序在執(zhí)行過程中遇到了異常或錯誤而異常終止

  • 由于操作系統(tǒng)出現(xiàn)錯誤而導致Java虛擬機進程終止


向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

jvm j
AI