JVM的類加載機(jī)制全面解析

什么是類加載機(jī)制

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

類的生命周期

類從被加載到內(nèi)存中,到被卸載出內(nèi)存,一共分為以下幾步:

  • 加載(Loading)
  • 驗(yàn)證(Verification)
  • 準(zhǔn)備(Preparation)
  • 解析(Resolution)
  • 初始化(Initialization)
  • 使用(Using)
  • 卸載(Unloading)
    類加載的全過程,包括其中的加載、驗(yàn)證、準(zhǔn)備、解析、初始化幾個(gè)階段。

加載

加載是類加載的第一階段,在這一步中JVM規(guī)范要求完成了以下三件事:

通過一個(gè)類的全限定名來獲取定義這個(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ì)象。
以上要求其實(shí)并不具體,JVM的具體實(shí)現(xiàn)和應(yīng)用都是比較靈活的。比如:獲取這個(gè)類的二進(jìn)制字節(jié)流,并沒有說從哪獲取,怎么獲取,于是就有了從壓縮包中讀取(jar、war、ear)、從網(wǎng)絡(luò)中獲取(Applet)、運(yùn)行時(shí)計(jì)算生成(動(dòng)態(tài)代理)。對(duì)于不是數(shù)組的類的加載,我們可以定義自己的類加載器去控制字節(jié)流的獲取方式。但是,對(duì)于數(shù)組類就不一樣了,因?yàn)閿?shù)組類本身不是通過類加載器創(chuàng)建的,而是JVM直接創(chuàng)建的。

驗(yàn)證

這一階段是為了保證Class文件的字節(jié)流中包含的信息符合當(dāng)前JVM的要求,并且不危害JVM自身的安全。大致分為以下四個(gè)階段:

文件格式驗(yàn)證

驗(yàn)證字節(jié)流是否符合Class文件格式的規(guī)范,能不能被當(dāng)前JVM處理。驗(yàn)證點(diǎn)比較多,比如:是否以魔數(shù)0xCAFEBABE開頭、主次版本號(hào)是否在當(dāng)前JVM的處理范圍內(nèi)、常量池的常量是否有不被支持的常量類型、CONSTANT_Utf8_info類型的常量中是否有不符合UTF8編碼的數(shù)據(jù)等等。這個(gè)階段是基于二進(jìn)制字節(jié)流進(jìn)行驗(yàn)證的,只有這個(gè)階段驗(yàn)證通過了,字節(jié)流才能進(jìn)入內(nèi)存的方法區(qū)儲(chǔ)存。

元數(shù)據(jù)驗(yàn)證

這個(gè)階段主要是對(duì)類的元數(shù)據(jù)信息進(jìn)行語(yǔ)義分析和校驗(yàn),保證不存在不符合Java語(yǔ)言規(guī)范的元數(shù)據(jù)信息。比如:除了java.lang.Object以外的類是否有父類、是否繼承了一個(gè)不允許被繼承的類、非抽象類是否實(shí)現(xiàn)了其父類或接口中要求實(shí)現(xiàn)的所有方法、是否覆蓋了父類的final字段等等。

字節(jié)碼校驗(yàn)

這個(gè)階段通過數(shù)據(jù)流和控制流分析,確保程序語(yǔ)義是合法的、符合邏輯的。比如:放置和使用操作棧時(shí)數(shù)據(jù)類型保證一致、保證跳轉(zhuǎn)指令不會(huì)跳轉(zhuǎn)到方法體以外的字節(jié)碼指令上、保證方法體中的類型轉(zhuǎn)換是有效的等等。

符號(hào)引用校驗(yàn)

這個(gè)階段是對(duì)類自身以外(常量池中的各種符號(hào)引用)的信息進(jìn)行匹配性校驗(yàn),它發(fā)生在解析步驟中,確保解析能正常執(zhí)行,比如:符號(hào)引用中通過字符串描述的全限定名是否能找到對(duì)應(yīng)的類、符號(hào)引用中的類字段方法的訪問性是否可以訪問當(dāng)前類等等。

準(zhǔn)備

在這個(gè)階段里,為靜態(tài)變量分配內(nèi)存并設(shè)置靜態(tài)變量初始值。這里說的初始值通常情況下,不是代碼中寫的初始值,而是數(shù)據(jù)類型的零值。代碼中寫的初始值,是在初始化階段賦值的。如果是靜態(tài)常量(被final修飾),這個(gè)階段就會(huì)被直接賦值為代碼中寫的初始值。

解析

在這個(gè)階段里,JVM把常量池內(nèi)的符號(hào)引用替換為直接引用。符號(hào)引用以一組符號(hào)來描述所引用的目標(biāo),符號(hào)可以是任何形式的字面量,只要使用時(shí)能無歧義地定位到目標(biāo)即可,它和JVM實(shí)現(xiàn)的內(nèi)存布局無關(guān)。直接引用可以是直接指向目標(biāo)的指針、相對(duì)偏移量或是一個(gè)能間接定位到目標(biāo)的句柄,它是和JVM實(shí)現(xiàn)的內(nèi)存布局相關(guān)的。如果有了直接引用,那么引用的目標(biāo)肯定在內(nèi)存中存在。

解析主要針對(duì)類或接口、字段、類方法、接口方法、方法類型、方法句柄和調(diào)用點(diǎn)限定符的符號(hào)引用進(jìn)行,分別對(duì)應(yīng)常量池的CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info、CONSTANT_InterfaceMethodref_info、CONSTANT_MethodType_info、CONSTANT_MethodHandle_info和CONSTANT_InvokeDynamic_info。

初始化

初始化階段才真正開始執(zhí)行類中定義的字節(jié)碼,也是執(zhí)行類構(gòu)造器()方法的過程。()方法是由編譯器自動(dòng)收集類中的所有靜態(tài)變量的賦值動(dòng)作和靜態(tài)語(yǔ)句塊中的語(yǔ)句合并產(chǎn)生的,編譯器收集的順序是用語(yǔ)句在源文件中出現(xiàn)的順序所決定的,靜態(tài)語(yǔ)句塊只能訪問到定義在靜態(tài)語(yǔ)句塊之前的變量,定義在它之后的變量,靜態(tài)語(yǔ)句塊可以賦值,但是不能訪問。

JVM會(huì)保證在子類的()方法執(zhí)行之前,父類的()方法已經(jīng)執(zhí)行完畢,也就是說父類中定義的靜態(tài)語(yǔ)句塊要優(yōu)先于子類的變量賦值操作。如果類沒有靜態(tài)語(yǔ)句塊,也沒有對(duì)靜態(tài)變量賦值,編譯器就不會(huì)為這個(gè)類生成()方法。接口的()方法不需要先執(zhí)行父接口的()方法,只有當(dāng)父接口中定義的變量使用時(shí),父接口才會(huì)被初始化。

JVM會(huì)保證一個(gè)類的()方法在多線程環(huán)境中被正確地加鎖、同步。如果一個(gè)線程在執(zhí)行這個(gè)類的()方法,其他線程都需要阻塞等待,當(dāng)()方法執(zhí)行完后,其他線程也不會(huì)再次進(jìn)入()方法。同一個(gè)類加載器下,一個(gè)類只會(huì)被初始化一次。

結(jié)語(yǔ)

這次我們了解了類加載過程的幾個(gè)階段,分別是加載、驗(yàn)證、準(zhǔn)備、解析和初始化。加載是把二進(jìn)制字節(jié)碼載入內(nèi)存,驗(yàn)證是校驗(yàn)字節(jié)流中包含的信息是否符合當(dāng)要求,準(zhǔn)備是為靜態(tài)變量分配內(nèi)存并設(shè)置靜態(tài)變量初始值,解析是把常量池內(nèi)的符號(hào)引用替換為直接引用,初始化是執(zhí)行所有靜態(tài)變量的賦值動(dòng)作和靜態(tài)語(yǔ)句塊中的語(yǔ)句。

打個(gè)廣告,本人博客地址是:風(fēng)吟個(gè)人博客

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,494評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,714評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,410評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,940評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,776評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,210評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評(píng)論 1 286
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,654評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

推薦閱讀更多精彩內(nèi)容

  • 什么是類加載機(jī)制 JVM把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn)、轉(zhuǎn)換解析和初始化,最終形成可以...
    p712long閱讀 223評(píng)論 0 0
  • 代碼編譯的結(jié)果從本地機(jī)器碼轉(zhuǎn)變?yōu)樽止?jié)碼,是存儲(chǔ)格式發(fā)展的一小步,確實(shí)編譯語(yǔ)言發(fā)展的一大步。 虛擬機(jī)把描述類的數(shù)據(jù)從...
    胡二囧閱讀 966評(píng)論 0 0
  • 上篇文章中,我們介紹了 .class 文件的結(jié)構(gòu),.class 文件只是一個(gè)靜態(tài)的文件,那 JVM 是加載 .cl...
    lijiankun24閱讀 3,008評(píng)論 2 9
  • JVM類加載機(jī)制 概述 類加載過程 加載 通過類的全限定名獲取類的二進(jìn)制流 將靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)...
    東溪95閱讀 3,055評(píng)論 0 15
  • 有興趣可以先參考前面的幾篇JVM總結(jié): JVM自動(dòng)內(nèi)存管理機(jī)制-Java內(nèi)存區(qū)域(上) JVM自動(dòng)內(nèi)存管理機(jī)制-J...
    零點(diǎn)145閱讀 249評(píng)論 0 0