一、內(nèi)存結(jié)構(gòu)
類加載子系統(tǒng)的職責(zé)是:加載class文件到內(nèi)存中。
完整的內(nèi)存結(jié)構(gòu)如下:
二、類加載過(guò)程
類加載過(guò)程總體分為L(zhǎng)oading(加載)、Linking(鏈接)、Initialization(初始化)三個(gè)環(huán)節(jié),在Linking階段又細(xì)分為Verification(驗(yàn)證)、Preparation(準(zhǔn)備)、Resolution(解析)三個(gè)環(huán)節(jié)。
1. 加載(Loading)
- 通過(guò)一個(gè)類的全限定名獲取定義此類的二進(jìn)制字節(jié)流
- 將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)
- 在內(nèi)存中生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象,作為方法區(qū)這個(gè)類的各種數(shù)據(jù)的訪問(wèn)入口
補(bǔ)充:加載class文件的方式
- 從本地系統(tǒng)中直接加載
- 通過(guò)網(wǎng)絡(luò)獲取,典型場(chǎng)景:Web Applet
- 從zip壓縮包中讀取,成為日后jar、war格式的基礎(chǔ)
- 運(yùn)行時(shí)計(jì)算生成,使用最多的是:動(dòng)態(tài)代理技術(shù)
- 由其他文件生成,典型場(chǎng)景:JSP應(yīng)用
- 從專有數(shù)據(jù)庫(kù)中提取.class文件,比較少見
- 從加密文件中獲取,典型的防Class文件被反編譯的保護(hù)措施
2. 鏈接(Linking)
(1)驗(yàn)證(Verification)
- 驗(yàn)證字節(jié)碼文件的字節(jié)流中包含信息符合虛擬機(jī)規(guī)范,以防止不正常的字節(jié)流危害虛擬機(jī)安全。所有能被JVM識(shí)別的字節(jié)碼文件,它的有效起始都是CA FE BA BE,它是JVM識(shí)別的一個(gè)標(biāo)識(shí)。
- 主要包括四種驗(yàn)證,文件格式驗(yàn)證,元數(shù)據(jù)驗(yàn)證,字節(jié)碼驗(yàn)證,符號(hào)引用驗(yàn)證。
- 驗(yàn)證錯(cuò)誤會(huì)報(bào)VerifyError
????????我們使用BinaryViewer打開.class文件,發(fā)現(xiàn)他的開頭都是 CAFE BABE。
(2)準(zhǔn)備(Preparation)
- 為類變量(非final修飾的static變量)分配內(nèi)存(在方法區(qū)),設(shè)置其初始值(零值)
- 如果 static 變量是 final 的基本類型,以及字符串常量,那么編譯階段值就確定了,賦值在準(zhǔn)備階段完成
- 如果 static 變量是 final 的引用類型,即new的對(duì)象,賦值在初始化階段完成
- 實(shí)例變量不會(huì)被分配初始化,實(shí)例變量隨對(duì)象被分配到Java堆中。
(3)解析(Resolution)(存疑)
- 將常量池內(nèi)的符號(hào)應(yīng)用轉(zhuǎn)換為直接引用。
- 符號(hào)引用是一組來(lái)描述所引用的目標(biāo)。直接引用就是直接指向目標(biāo)的指針、相對(duì)偏移量或者一個(gè)間接定位到目標(biāo)的句柄。
3. 初始化(Initialization)
????????(1)初始化階段就是執(zhí)行類構(gòu)造器方法<clinit>()的過(guò)程。此方法不需定義,是javac編譯器自動(dòng)收集類中的所有類變量的賦值動(dòng)作和靜態(tài)代碼塊中的語(yǔ)句合并而來(lái)。
????????也就是說(shuō),沒有類變量和靜態(tài)代碼塊,就不會(huì)有<clinit>,比如下面這段代碼:
????????在字節(jié)碼文件中,一個(gè)類的方法會(huì)被解析到methods文件目錄下,構(gòu)造器對(duì)應(yīng)目錄下的<init>()方法, main()就對(duì)應(yīng)main()。
????????我們使用idea的jclasslib插件查看method,發(fā)現(xiàn)只有類構(gòu)造器<init>和main方法。
????????(2)構(gòu)造器方法中指令按語(yǔ)句在源文件中出現(xiàn)的順序執(zhí)行。
????????結(jié)合如下代碼進(jìn)行理解:
? ? ? ? 1. 我們?cè)陟o態(tài)代碼塊中使用了類變量number,但是number的定義是在整個(gè)靜態(tài)代碼塊之后,能這樣做的原因是,在鏈接的準(zhǔn)備階段,我們已經(jīng)為number分配了內(nèi)存,并設(shè)置初始值為0.
? ? ? ? 2. 但是不能在聲明之前進(jìn)行引用。
????????使用jclasslib查看<clinit>的代碼,如下:
? ? ? ? 這串代碼是與文件里語(yǔ)句的順序?qū)?yīng)起來(lái)的。
?????????因此執(zhí)行這段代碼后,number的值應(yīng)該是10,而不是20.
? ? ? ? (3)若該類具有父類,JVM會(huì)保證子類的<clinit>()執(zhí)行前,父類的<clinit>()已經(jīng)執(zhí)行完畢。
????????(4)虛擬機(jī)必須保證一個(gè)類的<clinit>()方法在多線程下被同步加鎖。
????????以這段代碼為例,嘗試多線程加載一個(gè)類。
????????執(zhí)行這段代碼的結(jié)果是,永遠(yuǎn)會(huì)有一個(gè)線程無(wú)法結(jié)束,因?yàn)?lt;clinit>只會(huì)有一次,也就是說(shuō)類只能被加載一次。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-572954.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-572954.html
到了這里,關(guān)于[JVM] 2. 類加載子系統(tǒng)(1)-- 內(nèi)存結(jié)構(gòu)、類加載子系統(tǒng)概述的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!