JVM類加載機制

虛擬機把Class文件(描述類的數(shù)據(jù))加載到內(nèi)存沙咏,并對數(shù)據(jù)進行校驗、轉(zhuǎn)換解析和初始化班套,最終形成可以被虛擬機直接使用的Java類型肢藐,這就是類加載機制

Java中吱韭,類顯性的加載吆豹、連接、初始化都是在 運行期 完成理盆。

Class文件是一串二進制的字節(jié)流痘煤。


1、類加載總體流程圖

這里寫圖片描述

類的整個生命周期分為以上七個階段:加載猿规、驗證衷快、準(zhǔn)備、解析姨俩、初始化蘸拔、使用、卸載环葵。

類加載的全過程包括5個階段:加載调窍、驗證、準(zhǔn)備张遭、解析邓萨、初始化。


2、虛擬機規(guī)范規(guī)定了如下幾種情況就必須要進行初始化

  • 遇到new先誉、getstatic湿刽、putstatic、invokestatic指令時褐耳,對應(yīng)到程序中就是使用到new實例化對象時诈闺、讀取或設(shè)置類靜態(tài)字段時(非final)、調(diào)用靜態(tài)方法時铃芦。需要進行初始化雅镊。

  • 使用java.lang.reflect包的方法對類進行反射調(diào)用時,需要進行初始化刃滓。

  • 使用一個類時仁烹,若其父類還未初始化,則需先初始化其父類咧虎。

  • 虛擬機啟動時卓缰,包含main方法的類(主類),虛擬機會將其初始化砰诵。

  • java.lang.invoke.MethodHandle實例最后的解析結(jié)果REF_getStatic征唬、REF_putStatic、REF_invokeStatic方法句柄茁彭,并且這個方法句柄對應(yīng)的類沒有進行初始化总寒,則需要先進行初始化。

以上五種情況稱為主動使用理肺,其他的情況均稱為被動使用摄闸,被動使用不會導(dǎo)致初始化。


3妹萨、類加載的全過程

類加載的全過程包括5個階段:加載年枕、驗證、準(zhǔn)備乎完、解析画切、初始化

3.1 加載

加載階段虛擬機需要完成如下事情:

  1. 通過類的全限定名來獲取此類的二進制字節(jié)流囱怕。

  2. 將二進制字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)。

  3. 在內(nèi)存中生成一個代表這個類的java.lang.Class對象毫别,作為方法區(qū)這個類的各種數(shù)據(jù)的訪問入口娃弓。

對于 數(shù)組 類而言,數(shù)組類由java虛擬機直接創(chuàng)建岛宦,不通過類加載器創(chuàng)建台丛。數(shù)組類的創(chuàng)建過程如下:

  • 如果數(shù)組元素類型是引用類型,就采用雙親委派模型進行加載(之后會介紹),數(shù)組類將在加載該元素類型的類名稱空間上被標(biāo)識挽霉。

  • 如果數(shù)組元素類型為基本類型防嗡,數(shù)組類被標(biāo)記為與引導(dǎo)類加載器關(guān)聯(lián)。

  • 數(shù)組類的可見性與其元素類型可見性一致侠坎,如果元素類型不是引用類型蚁趁,那數(shù)組類的可見性默認(rèn)為public。

創(chuàng)建的Class對象存放在方法區(qū)中实胸。對象絕大多數(shù)放在堆中他嫡,Class對象是一個例外。

3.2 驗證

此階段是確保class文件的字節(jié)流包含的信息符合虛擬機的要求庐完。主要會進行如下的驗證钢属。

  1. 文件格式驗證

驗證字節(jié)流是否符合Class文件格式規(guī)范。如是否以魔數(shù)開頭门躯、主次版本號是否能被虛擬機處理淆党、常量池的常量中是否有不被支持的常量類型等等。

  1. 元數(shù)據(jù)驗證

對字節(jié)碼描述的信息進行語義分析讶凉。如這個類是否有父類染乌、這個類是否繼承了不允許被繼承的類、非抽象類是否實現(xiàn)了父類或接口中要求實現(xiàn)的所有方法等等缀遍。

  1. 字節(jié)碼驗證

分析數(shù)據(jù)流和控制流慕匠,確定程序語義是否合法,符合邏輯域醇。如任意時刻操作數(shù)棧的數(shù)據(jù)類型與指令代碼序列都能配合工作台谊、保證跳轉(zhuǎn)指令不會跳轉(zhuǎn)到方法體以外的字節(jié)碼指令上等等。

  1. 符號引用驗證

符號引用轉(zhuǎn)化為直接引用的時候進行驗證譬挚。如符號引用中通過字符串描述的全限定名是否能夠找到對應(yīng)的類锅铅、指定類中是否存在符合方法的字段描述符以及簡單名稱所描述的方法和字段等等。

3.3 準(zhǔn)備

類變量(被static修飾的變量)分配內(nèi)存并為類變量設(shè)置系統(tǒng)初始值的階段减宣,這些類變量所使用的內(nèi)存都將在方法區(qū)進行分配盐须。靜態(tài)字段(非final)會被賦予系統(tǒng)默認(rèn)值,而對于常量字段(final漆腌、static)贼邓,在準(zhǔn)備階段直接賦予用戶設(shè)定的值。

3.4 解析

常量池 中的 符號引用 替換為 直接引用 的過程闷尿。

符號引用:符號引用以一組無歧義的符號來描述所引用的目標(biāo)塑径。符號引用與虛擬機的內(nèi)存布局無關(guān),引用的目標(biāo)并不一定已經(jīng)加載到內(nèi)存中填具。

直接引用:直接引用可以是直接指向目標(biāo)的指針统舀、相對偏移量或是一個能夠間接定位到目標(biāo)的句柄。直接引用和虛擬機實現(xiàn)的內(nèi)存布局有關(guān),引用的目標(biāo)必須已經(jīng)存在于內(nèi)存中誉简。

解析動作主要是針對7中常量類型:

CONSTANT_Class_info
CONSTANT_Fieldref_info
CONSTANT_Methodref_info
CONSTANT_InterfaceMethodref_info
CONSTANT_MethodType_info
CONSTANT_MethodHandle_info
CONSTANT_InvokeDynamic_info

3.5 初始化

在此階段碉就,才開始真正執(zhí)行用戶自定的java代碼。在準(zhǔn)備階段闷串,類變量已經(jīng)被賦予了系統(tǒng)默認(rèn)值瓮钥,而在初始化階段,會賦予用戶自定義的值窿克。

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

<clinit>() 方法

  1. 由編譯器收集類中的所有類變量的賦值動作(如果僅僅只是聲明,不會被收集)和靜態(tài)語句塊中的語句合并產(chǎn)生的年叮,收集順序按照語句在源文件中出現(xiàn)的順序所決定具被;在靜態(tài)語句塊中只能訪問定義在靜態(tài)語句之前的變量;而對于定義在靜態(tài)語句塊之后的變量一姿,在前面的靜態(tài)語句塊可以對它進行賦值,但是不能夠訪問跃惫。

  2. 不需要顯示調(diào)用父類構(gòu)造器叮叹。虛擬機會保證在子類的<clinit>()方法執(zhí)行之前,父類的<clinit>()方法已經(jīng)執(zhí)行完畢爆存,所以蛉顽,第一個被執(zhí)行的<clinit>()方法的類肯定是java.lang.Object。

  3. 父類中定義的靜態(tài)語句塊優(yōu)先于子類的靜態(tài)語句先较。

  4. <clinit>()方法對類和接口都不是必須的携冤,若類中沒有靜態(tài)語句塊和靜態(tài)變量賦值操作,則不會生成<clinit>()方法闲勺。

  5. 接口中不能使用靜態(tài)語句塊曾棕,但任然有變量初始化的賦值操作,因此接口也會生成<clinit>()方法菜循。不同的是翘地,執(zhí)行接口的<clinit>()方法不需要先執(zhí)行父接口的<clinit>()方法,只有在使用了父接口的變量時癌幕,父接口才會進行初始化衙耕。接口的實現(xiàn)類在初始化時也不會執(zhí)行接口的<clinit>()方法。

  6. 虛擬機會保證<clinit>()方法在多線程環(huán)境中會被正確的加鎖勺远、同步臭杰。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市谚中,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖宪塔,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件磁奖,死亡現(xiàn)場離奇詭異,居然都是意外死亡某筐,警方通過查閱死者的電腦和手機比搭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來南誊,“玉大人身诺,你說我怎么就攤上這事〕簦” “怎么了霉赡?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長幔托。 經(jīng)常有香客問我穴亏,道長,這世上最難降的妖魔是什么重挑? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任嗓化,我火速辦了婚禮,結(jié)果婚禮上谬哀,老公的妹妹穿的比我還像新娘刺覆。我一直安慰自己,他們只是感情好史煎,可當(dāng)我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布谦屑。 她就那樣靜靜地躺著,像睡著了一般劲室。 火紅的嫁衣襯著肌膚如雪伦仍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天很洋,我揣著相機與錄音充蓝,去河邊找鬼。 笑死喉磁,一個胖子當(dāng)著我的面吹牛谓苟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播协怒,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼涝焙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了孕暇?” 一聲冷哼從身側(cè)響起仑撞,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤赤兴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后隧哮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體桶良,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年沮翔,在試婚紗的時候發(fā)現(xiàn)自己被綠了陨帆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡采蚀,死狀恐怖疲牵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情榆鼠,我是刑警寧澤纲爸,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站璧眠,受9級特大地震影響缩焦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜责静,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一袁滥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧灾螃,春花似錦题翻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至熄赡,卻和暖如春姜挺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背彼硫。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工炊豪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拧篮。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓词渤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親串绩。 傳聞我的和親對象是個殘疾皇子缺虐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,781評論 2 354

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

  • JVM類加載機制 概述 類加載過程 加載 通過類的全限定名獲取類的二進制流 將靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)...
    東溪95閱讀 3,033評論 0 15
  • 簡述:虛擬機把描述類的數(shù)據(jù)從class文件加載到內(nèi)存,并對數(shù)據(jù)進行校驗礁凡、轉(zhuǎn)換解析和初始化高氮,最終形成可以被虛擬機直接...
    卡巴拉的樹閱讀 1,881評論 1 6
  • 概述 虛擬機把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存慧妄,并對數(shù)據(jù)進行校驗,轉(zhuǎn)換纫溃,解析和初始化腰涧,最終形成可以被虛擬機直...
    lwd45閱讀 1,698評論 0 16
  • 簡介 代碼編譯的結(jié)果從本地機器碼轉(zhuǎn)變?yōu)樽止?jié)碼,是存儲格式發(fā)展的一小步紊浩,卻是編程語言發(fā)展的一大步。與那些在編譯時需要...
    黃俊彬閱讀 345評論 0 6
  • 在Java語言里疗锐,類的加載坊谁、連接和初始化都是在程序運行期間完成的。這種方式雖然在性能上會一定的開銷滑臊,但是它會是Ja...
    MentallyL閱讀 257評論 0 0