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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

?

類加載機制概念

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

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

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

工作機制

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

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

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規(guī)范允許類加載器在預料某個類將要被使用時就預先加載它,如果在預先加載的過程中遇到了.class文件缺失或存在錯誤,類加載器必須在程序首次主動使用該類時才報告錯誤(LinkageError錯誤)如果這個類一直沒有被程序主動使用,那么類加載器就不會報告錯誤。

加載.class文件的方式有:

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

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

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

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

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

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

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

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

2. 驗證

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

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

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

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

? ? ? ? ? ? ? ? ? ? ?

3. 準備

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


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

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

4. 解析

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

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

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

5. 初始化

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


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

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

JVM初始化步驟

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

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

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

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

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

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

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

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

(6) Java虛擬機啟動時被標明為啟動類的類(Java Test),直接使用java.exe命令來運行某個主類

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

?

結(jié)束生命周期

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

總結(jié)

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

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