JVM基礎之類加載機制(三)

代碼編譯后產生字節(jié)碼而不是本地機器碼匿乃,是存儲格式的一小步,卻是編程語言的一大步豌汇。

一幢炸、類加載機制概述

虛擬機將描述類的.class文件加載到內存,并對數(shù)據(jù)進行校驗瘤礁,轉換解析和初始化阳懂,最終生成可以被虛擬機直接使用的對象。Java中類型的加載柜思、連接和初始化在程序運行期間完成岩调,會有性能開銷,但為Java程序提供了高度的靈活性赡盘,是天生的可動態(tài)擴展的語言号枕。

二、類加載的時機

  1. 類在虛擬機中的生命周期
  • 加載陨享、驗證葱淳、準備钝腺、解析、初始化赞厕、使用和卸載七個階段且順序是確定的艳狐,驗證、準備皿桑、解析統(tǒng)稱為連接毫目。
  • 解析階段某些情況下可以在初始化之后開始,這是為了支持Java語言的運行時綁定(又稱動態(tài)綁定或晚期綁定)诲侮。
  1. 初始化開始的時機
  • 遇到new镀虐、getstatic、putstatic沟绪、invokestatic這4條字節(jié)碼指令時刮便,對應Java代碼場景是:使用new實例化對象、讀取或設置類的靜態(tài)字段(final修飾绽慈,已在編譯期把結果放入常量池的靜態(tài)字段除外)恨旱、調用類的靜態(tài)方法。
  • 使用java.lang.reflect包的方法對類進行反射調用的時候久信,如果類未進行過初始化則觸發(fā)其初始化窖杀。
  • 初始化類時,其父類未進行初始化則先對父類進行初始化裙士。
  • 虛擬機啟動時入客,要執(zhí)行的主類(包含main方法的類)虛擬機會先初始化這個主類。
  • 使用動態(tài)語言支持時腿椎,java.lang.invoke.MethodHandle實例的解析結果REF_getStatic桌硫、REF_putStatic、REF_invokeStatic的方法句柄啃炸,并且這個方法句柄對應的類沒有進行過初始化铆隘,需要先觸發(fā)其初始化。
  • 對于上述5中場景南用,是“有且只有”的能觸發(fā)初始化的情況膀钠,稱為對一個類進行主動引用,除此之外不會觸發(fā)初始化裹虫,稱為被動引用肿嘲。
  • 靜態(tài)塊(static{}修飾的代碼塊)只會在初始化時執(zhí)行,定義數(shù)組時不會觸發(fā)類的初始化筑公,靜態(tài)常量會在編譯時被轉化為對常量池中值的引用雳窟。
  • 接口(interface)進行初始化時,不要求父接口全部完成初始化匣屡,只有在真正使用到父接口的時候(如引用接口中定義的常量)才會初始化封救。
  • 數(shù)組初始化時拇涤,不會觸發(fā)類的初始化。

三誉结、類加載的過程

  1. 加載階段
  • “加載”是“類加載(class loading)”過程的一個階段鹅士,需要在這個階段完成三件事情。
  • 通過類的全限定名來獲取定義類的二進制字節(jié)流搓彻,將字節(jié)流代表的靜態(tài)存儲結構轉化為方法區(qū)的運行時數(shù)據(jù)結構如绸,在內存中生成代表類的java.lang.Class對象作為方法區(qū)中這個類的訪問入口。
  • 加載階段完成后旭贬,虛擬機外部的二進制字節(jié)流就按照虛擬機所需的格式存儲在方法區(qū)中,方法區(qū)中數(shù)據(jù)存儲格式又虛擬機實現(xiàn)自行定義搪泳,虛擬機規(guī)范沒有規(guī)定稀轨。
  1. 驗證階段
  • 驗證是連接階段的第一步,確保Class文件的字節(jié)流中包含的信息符合當前虛擬機的要求岸军,不會危害虛擬機的安全奋刽。
  • 大致完成四個階段的檢查動作:文件格式驗證、元數(shù)據(jù)驗證艰赞、字節(jié)碼驗證佣谐、符號引用驗證。
  • 文件格式驗證方妖,是否以魔數(shù)0xCAFEBABE開頭狭魂,主、次版本號是否在當前虛擬機處理范圍之內党觅,常量池中是否有不被支持的常量類型等等雌澄。該階段保證輸入的字節(jié)流能正確地解析并存儲于方法區(qū),格式上符合Java類型信息的要求杯瞻,因此后面的三個驗證階段是基于方法區(qū)的存儲結構進行镐牺,不直接操作字節(jié)流。
  • 元數(shù)據(jù)驗證魁莉,對字節(jié)碼描述的信息進行語義分析睬涧,保證其描述的信息符合Java語言規(guī)范的要求,如:這個類是否有父類旗唁、是否繼承了被final修飾的父類畦浓、如果不是抽象類是否實現(xiàn)了父類或接口之中要求實現(xiàn)的方法等等。
  • 字節(jié)碼驗證逆皮,是驗證階段最復雜的宅粥,通過數(shù)據(jù)流和控制流分析確定程序語義是合法的、符合邏輯的电谣,保證被校驗的類的方法在運行時不會危害虛擬機的安全秽梅,如類型不匹配的情況抹蚀。
  • 符號引用驗證,對類自身以外的信息進行匹配性校驗企垦,如符號引用中通過字符串描述的全限定名是否能找到對應的類环壤。
  1. 準備階段
  • 準備階段是正式為類變量分配內存并設置類變量初始值的階段,變量需使用的內存都將在方法區(qū)中進行分配钞诡。需要注意的是郑现,該階段進行內存分配的僅有類變量(被static修飾的變量),不包括實例變量荧降。類變量按類型在內存分配空間后接箫,初始值為零值(int:0,long:0L朵诫,short:(short)0辛友,char:'\u0000',byte:(byte)0剪返,boolean:false废累,float:0.0f,double:0.0d脱盲,reference:null)邑滨。如果是被final修飾的變量,編譯時javac會為變量生成ConstantValue屬性钱反,在該階段虛擬機根據(jù)ConstantValue屬性將變量賦值掖看。
  1. 解析階段
  • 該階段是虛擬機將常量池內的符號引用替換為直接引用的過程。
  • 虛擬機規(guī)范沒有規(guī)定解析階段發(fā)生的具體時間诈铛,只要求在執(zhí)行用于操作符號引用的字節(jié)碼指令之前乙各,先對它們使用的符號引用進行解析。
  1. 初始化
  • 該階段根據(jù)程序員通過程序制定的主觀計劃去初始化類變量和其他資源幢竹,即該階段是執(zhí)行類構造器<clinit>()方法的過程耳峦。
  • <clinit>()方法是由編譯器自動收集類中的所有類變量的賦值動作和靜態(tài)語句塊中的語句合并產生,收集的順序是由語句在源文件中出現(xiàn)的順序所決定的焕毫,靜態(tài)語句塊只能訪問到定義在靜態(tài)語句塊之前的變量蹲坷,在其之后定義的變量不能訪問但可以賦值。

四邑飒、類加載器

  1. 類與類加載器
  • 虛擬機把類加載階段中循签,“通過全限定名獲取描述此類的二進制字節(jié)流”交給虛擬機外部去實現(xiàn),以便讓應用程序自己決定如何去獲取所需要的類疙咸,實現(xiàn)這個動作的代碼模塊稱為“類加載器”县匠。
  • 每一個類加載器都擁有獨立的類名稱空間,比較兩個類是否“相等”,只有在兩個類是由同一個類加載器加載的前提下才有意義乞旦。
  1. 雙親委派模式
  • 從Java虛擬機角度看贼穆,有兩種不同的類加載器,一種試啟動類加載器(Bootstrap ClassLoader)兰粉,在Hotspot中由C++語言實現(xiàn)故痊;一種是所有其他的類加載器,由Java語言實現(xiàn)玖姑,獨立于虛擬機外部愕秫,并且繼承自java.lang.ClassLoader類。
  • 大部分時候程序會用到三種系統(tǒng)提供的類加載器焰络,包括:啟動類加載器戴甩,負責將存在<JAVA_HOME>\lib目錄中的,或被-Xbootclasspath參數(shù)指定的路徑中的類庫加載到虛擬機闪彼;擴展類加載器等恐,它負責加載<JAVA_HOME>\lib\ext目錄中,或java.ext.dirs系統(tǒng)變量指定路徑中的所有類庫备蚓;應用程序類加載器(系統(tǒng)類加載器),由ClassLoader.getSystemClassLoader()方法獲取囱稽,如果程序沒有自定義過類加載器郊尝,一般情況下這個就是程序默認的類加載器。
  • 啟動類加載器 <--- 擴展類加載器 <--- 應用程序類加載器 <--- 自定義類加載器战惊,這樣的層次關系稱為類加載器的雙親委派模型(Parents Delegation Model)流昏。
  • 雙親委派模型在工作時,如果一個類加載器收到了類加載的請求吞获,它首先不會自己嘗試加載况凉,而是將請求委派給父類加載器去完成,每一個層次的類加載器都是如此各拷。這樣可以保證任何一個類加載請求都是由同一個類加載器完成刁绒。

說明

  • 文中內容主要來自于《深入理解Java虛擬機》,更多內容請關注原著烤黍。
  • 此文是讀書時對重點知識的記錄知市,如有錯誤請一定指出。
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末速蕊,一起剝皮案震驚了整個濱河市嫂丙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌规哲,老刑警劉巖跟啤,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡隅肥,警方通過查閱死者的電腦和手機竿奏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來武福,“玉大人议双,你說我怎么就攤上這事∽狡” “怎么了平痰?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長伍纫。 經常有香客問我宗雇,道長,這世上最難降的妖魔是什么莹规? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任赔蒲,我火速辦了婚禮,結果婚禮上良漱,老公的妹妹穿的比我還像新娘舞虱。我一直安慰自己,他們只是感情好母市,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布矾兜。 她就那樣靜靜地躺著,像睡著了一般患久。 火紅的嫁衣襯著肌膚如雪椅寺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天蒋失,我揣著相機與錄音返帕,去河邊找鬼。 笑死篙挽,一個胖子當著我的面吹牛荆萤,可吹牛的內容都是我干的。 我是一名探鬼主播嫉髓,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼观腊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了算行?” 一聲冷哼從身側響起梧油,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎州邢,沒想到半個月后儡陨,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體褪子,經...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年骗村,在試婚紗的時候發(fā)現(xiàn)自己被綠了嫌褪。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡胚股,死狀恐怖笼痛,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情琅拌,我是刑警寧澤缨伊,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站进宝,受9級特大地震影響刻坊,放射性物質發(fā)生泄漏。R本人自食惡果不足惜党晋,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一谭胚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧未玻,春花似錦灾而、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至舞终,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間癣猾,已是汗流浹背敛劝。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留纷宇,地道東北人夸盟。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像像捶,于是被迫代替她去往敵國和親上陕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內容