日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JVM:类加载机制之类加载过程

發(fā)布時(shí)間:2025/3/21 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JVM:类加载机制之类加载过程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

類加載機(jī)制概念

?Java虛擬機(jī)把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存,并對數(shù)據(jù)進(jìn)行校驗(yàn)、準(zhǔn)備、解析和初始化,最終形成可以被虛擬機(jī)直接使用的Java類型,這就是虛擬機(jī)的加載機(jī)制。*

Class文件由類裝載器裝載后,在JVM中將形成一份描述Class結(jié)構(gòu)的元信息對象,通過該元信息對象可以獲知Class的結(jié)構(gòu)信息:如構(gòu)造函數(shù),屬性和方法等,Java允許用戶借由這個(gè)Class相關(guān)的元信息對象間接調(diào)用Class對象的功能,這里就是我們經(jīng)常能見到的Class類。

類從被加載到虛擬機(jī)內(nèi)存中開始,到卸載出內(nèi)存為止,它的整個(gè)生命周期包括了:加載(Loading)、驗(yàn)證(Verification)、準(zhǔn)備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(using)、和卸載(Unloading)七個(gè)階段。其中驗(yàn)證、準(zhǔn)備和解析三個(gè)部分統(tǒng)稱為連接(Linking),這七個(gè)階段的發(fā)生順序如下圖所示:?

工作機(jī)制

類裝載器就是尋找類的字節(jié)碼文件,并構(gòu)造出類在JVM內(nèi)部表示的對象組件。在Java中,類裝載器把一個(gè)類裝入JVM中,要經(jīng)過以下步驟:

?(1) 裝載:查找和導(dǎo)入Class文件; (2) 鏈接:把類的二進(jìn)制數(shù)據(jù)合并到JRE中;(a)校驗(yàn):檢查載入Class文件數(shù)據(jù)的正確性;(b)準(zhǔn)備:給類的靜態(tài)變量分配存儲空間;(c)解析:將符號引用轉(zhuǎn)成直接引用;(3) 初始化:對類的靜態(tài)變量,靜態(tài)代碼塊執(zhí)行初始化操作

1. 裝載(加載) (重點(diǎn))

什么是類的裝載

類的裝載指的是將類的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆區(qū)創(chuàng)建一個(gè)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)的接口。?

?

類加載器并不需要等到某個(gè)類被“首次主動使用”時(shí)再加載它,JVM規(guī)范允許類加載器在預(yù)料某個(gè)類將要被使用時(shí)就預(yù)先加載它,如果在預(yù)先加載的過程中遇到了.class文件缺失或存在錯(cuò)誤,類加載器必須在程序首次主動使用該類時(shí)才報(bào)告錯(cuò)誤(LinkageError錯(cuò)誤)如果這個(gè)類一直沒有被程序主動使用,那么類加載器就不會報(bào)告錯(cuò)誤。

加載.class文件的方式有:

1.從本地系統(tǒng)中直接加載

2.通過網(wǎng)絡(luò)下載.class文件

3.zipjar等歸檔文件中加載.class文件

4.從專有數(shù)據(jù)庫中提取.class文件

5. Java源文件動態(tài)編譯為.class文件

在了解了什么是類的加載后,回頭來再看jvm進(jìn)行類加載階段都做了什么。虛擬機(jī)需要完成以下三件事情:

1.通過一個(gè)類的全限定名稱來獲取定義此類的二進(jìn)制字節(jié)流。 2.將這個(gè)字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)。 3.java堆中生成一個(gè)代表這個(gè)類的java.lang.Class對象,作為方法區(qū)這些數(shù)據(jù)的訪問入口。

相對于類加載過程的其他階段,加載階段是開發(fā)期相對來說可控性比較強(qiáng)該階段既可以使用系統(tǒng)提供的類加載器完成,也可以由用戶自定義的類加載器來完成,開發(fā)人員可以通過定義自己的類加載器去控制字節(jié)流的獲取方式。關(guān)于這個(gè)過程的更多細(xì)節(jié),我會在下一節(jié)細(xì)說,類的加載。?
加載階段完成后,虛擬機(jī)外部的二進(jìn)制字節(jié)流就按照虛擬機(jī)所需的格式存儲在方法區(qū)之中,而且在Java堆中也創(chuàng)建一個(gè)java.lang.Class類的對象,這樣便可以通過該對象訪問方法區(qū)中的這些數(shù)據(jù)。

2. 驗(yàn)證

驗(yàn)證的目的是為了確保Class文件中的字節(jié)流包含的信息符合當(dāng)前虛擬機(jī)的要求,而且不會危害虛擬機(jī)自身的安全。不同的虛擬機(jī)對類驗(yàn)證的實(shí)現(xiàn)可能會有所不同,但大致都會完成以下四個(gè)階段的驗(yàn)證:文件格式的驗(yàn)證、元數(shù)據(jù)的驗(yàn)證、字節(jié)碼驗(yàn)證和符號引用驗(yàn)證。

?1)文件格式的驗(yàn)證:驗(yàn)證字節(jié)流是否符合Class文件格式的規(guī)范,并且能被當(dāng)前版本的虛擬機(jī)處理,該驗(yàn)證的主要目的是保證輸入的字節(jié)流能正確地解析并存儲于方法區(qū)之內(nèi)。經(jīng)過該階段的驗(yàn)證后,字節(jié)流才會進(jìn)入內(nèi)存的方法區(qū)中進(jìn)行存儲,后面的三個(gè)驗(yàn)證都是基于方法區(qū)的存儲結(jié)構(gòu)進(jìn)行的。 ?2)元數(shù)據(jù)驗(yàn)證:對類的元數(shù)據(jù)信息進(jìn)行語義校驗(yàn)(其實(shí)就是對類中的各數(shù)據(jù)類型進(jìn)行語法校驗(yàn)),保證不存在不符合Java語法規(guī)范的元數(shù)據(jù)信息。 ?3)字節(jié)碼驗(yàn)證:該階段驗(yàn)證的主要工作是進(jìn)行數(shù)據(jù)流和控制流分析,對類的方法體進(jìn)行校驗(yàn)分析,以保證被校驗(yàn)的類的方法在運(yùn)行時(shí)不會做出危害虛擬機(jī)安全的行為。 4 )符號引用驗(yàn)證:這是最后一個(gè)階段的驗(yàn)證,它發(fā)生在虛擬機(jī)將符號引用轉(zhuǎn)化為直接引用的時(shí)候(解析階段中發(fā)生該轉(zhuǎn)化,后面會有講解),主要是對類自身以外的信息(常量池中的各種符號引用)進(jìn)行匹配性的校驗(yàn)。

學(xué)習(xí)鏈接的驗(yàn)證這一步,需要了解class文件的結(jié)構(gòu)!

其實(shí)文件格式的驗(yàn)證、元數(shù)據(jù)的驗(yàn)證、字節(jié)碼的驗(yàn)證、符號引用的驗(yàn)證,其實(shí)都是保證class文件格式的正確性!

? ? ? ? ? ? ? ? ? ? ?

3. 準(zhǔn)備

準(zhǔn)備階段是正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段,這些內(nèi)存都將在方法區(qū)中進(jìn)行分配。?
注:(方法區(qū)


1)這時(shí)候進(jìn)行內(nèi)存分配的僅包括類變量(靜態(tài)變量static,而不包括實(shí)例變量,實(shí)例變量會在對象實(shí)例化時(shí)隨著對象一塊分配在Java中,例如上圖,這一階段,v只會被初始化為0,而不會賦值給1!賦值給1是在初始化階段才會按照用戶程序的設(shè)定值進(jìn)行初始化!但是,對于static final 變量會直接設(shè)值初始化!

2這里所設(shè)置的初始值通常情況下是數(shù)據(jù)類型默認(rèn)的零值(如0、0L、null、false等),而不是被在Java代碼中被顯式地賦予的值。

4. 解析

解析階段是虛擬機(jī)將常量池內(nèi)的符號引用替換為直接引用的過程。

比如說你的父類是com.imooc.src.Pojo,那么這就是符號引用,說白了就是一個(gè)字符串!但是我們在運(yùn)行的時(shí)候需要的是內(nèi)存的地址!因此此階段就是將這些字符串引用轉(zhuǎn)化為直接引用(也就是這個(gè)字符串引用在實(shí)際內(nèi)存中的地址)

符號引用(Symbolic Reference):符號引用以一組符號來描述所引用的目標(biāo),符號引用可以是任何形式的字面量,符號引用與虛擬機(jī)實(shí)現(xiàn)的內(nèi)存布局無關(guān),引用的目標(biāo)并不一定已經(jīng)在內(nèi)存中。 直接引用(Direct Reference):直接引用可以是直接指向目標(biāo)的指針、相對偏移量或是一個(gè)能間接定位到目標(biāo)的句柄。直接引用是與虛擬機(jī)實(shí)現(xiàn)的內(nèi)存布局相關(guān)的,同一個(gè)符號引用在不同的虛擬機(jī)實(shí)例上翻譯出來的直接引用一般都不相同,如果有了直接引用,那引用的目標(biāo)必定已經(jīng)在內(nèi)存中存在。 1、類或接口的解析:判斷所要轉(zhuǎn)化成的直接引用是對數(shù)組類型,還是普通的對象類型的引用,從而進(jìn)行不同的解析。 2、字段解析:對字段進(jìn)行解析時(shí),會先在本類中查找是否包含有簡單名稱和字段描述符都與目標(biāo)相匹配的字段,如果有,則查找結(jié)束;如果沒有,則會按照繼承關(guān)系從上往下遞歸搜索該類所實(shí)現(xiàn)的各個(gè)接口和它們的父接口,還沒有,則按照繼承關(guān)系從上往下遞歸搜索其父類,直至查找結(jié)束。 3、類方法解析:對類方法的解析與對字段解析的搜索步驟差不多,只是多了判斷該方法所處的是類還是接口的步驟,而且對類方法的匹配搜索,是先搜索父類,再搜索接口。 4、接口方法解析:與類方法解析步驟類似,只是接口不會有父類,因此,只遞歸向上搜索父接口就行了。

5. 初始化

類初始化階段是類加載過程的最后一步,前面的類加載過程中,除了加載(Loading)階段用戶應(yīng)用程序可以通過自定義類加載器參與之外,其余動作完全由虛擬機(jī)主導(dǎo)和控制。到了初始化階段,才真正開始執(zhí)行類中定義的Java程序代碼。?


初始化,為類的static靜態(tài)變量賦予正確的初始值,JVM負(fù)責(zé)對類進(jìn)行初始化,主要對類變量進(jìn)行初始化(靜態(tài)變量static。在Java中對類變量進(jìn)行初始值設(shè)定有兩種方式:

1、聲明類變量時(shí)指定初始值2、使用靜態(tài)代碼塊為類變量指定初始值

JVM初始化步驟

1、假如這個(gè)類還沒有被加載和連接,則程序先加載并連接該類 2、假如該類的直接父類還沒有被初始化,則先初始化其直接父類 3、假如類中有初始化語句,則系統(tǒng)依次執(zhí)行這些初始化語句

初始化階段是執(zhí)行類構(gòu)造器()方法的過程。

類初始化的觸發(fā)條件:只有當(dāng)對類的主動使用的時(shí)候才會導(dǎo)致類的初始化。

?(1) 創(chuàng)建類的實(shí)例,也就是new的方式

(2) 訪問某個(gè)類或接口的靜態(tài)變量,或者對該靜態(tài)變量賦值

(3) 調(diào)用類的靜態(tài)方法

(4) 反射(如Class.forName(“com.shengsiyuan.Test”)

(5) 初始化某個(gè)類的子類,則其父類也會被初始化

(6) Java虛擬機(jī)啟動時(shí)被標(biāo)明為啟動類的類(Java Test),直接使用java.exe命令來運(yùn)行某個(gè)主類

除此以外,所有其他方式都不會觸發(fā)初始化,稱為被動引用。?

?

結(jié)束生命周期

在以下情況的時(shí)候,Java虛擬機(jī)會結(jié)束生命周期?
1. 執(zhí)行了System.exit()方法?
2. 程序正常執(zhí)行結(jié)束?
3. 程序在執(zhí)行過程中遇到了異?;蝈e(cuò)誤而異常終止?
4. 由于操作系統(tǒng)出現(xiàn)錯(cuò)誤而導(dǎo)致Java虛擬機(jī)進(jìn)程終止

總結(jié)

以上是生活随笔為你收集整理的JVM:类加载机制之类加载过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。