jvm類加載機(jī)制過程

一诀拭、類加載過程

? ? ? ? Java類從被加載到虛擬機(jī)內(nèi)存中開始,到卸載出內(nèi)存為止煤蚌,它的整個(gè)生命周期包括:加載(Loading)耕挨、驗(yàn)證(Verification)、準(zhǔn)備(Preparation)尉桩、解析(Resolution)筒占、初始化(Initialization)、使用(Using)和卸載(Unloading)7個(gè)階段蜘犁。其中準(zhǔn)備翰苫、驗(yàn)證、解析3個(gè)部分統(tǒng)稱為連接(Linking)。如圖所示:

圖一:類加載流程圖

? ? ? 1.1奏窑、加載階段

????????????虛擬機(jī)JVM需要做三件事情:

????????????1.1.1导披、通過一個(gè)類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流(并沒有指明要從一個(gè)Class文件中獲取,可以從其他渠道埃唯,譬如:網(wǎng)絡(luò)撩匕、動(dòng)態(tài)生成、數(shù)據(jù)庫等)墨叛;

????????????1.1.2止毕、將這個(gè)字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu);

????????????1.1.3巍实、在內(nèi)存中生成一個(gè)代表這個(gè)類的java.lang.Class對象?[可通過類.class獲取該對象]滓技,作為方法區(qū)這個(gè)類的各種數(shù)據(jù)的訪問入口。



? ? ? ?1.2棚潦、連接階段

? ? ? ? ? ? 虛擬機(jī)JVM連接階段分三步走:

? ? ? ? ? ? 1 .2.1令漂、驗(yàn)證是連接階段的第一步,這一階段的目的是為了確保Class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求丸边,并且不會危害虛擬機(jī)自身的安全叠必。驗(yàn)證階段大致會完成4個(gè)階段的檢驗(yàn)動(dòng)作:文件格式驗(yàn)證、元數(shù)據(jù)驗(yàn)證妹窖、字節(jié)碼驗(yàn)證和符號引用驗(yàn)證纬朝。

????????????1.2.2、準(zhǔn)備階段是正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段骄呼,這些變量所使用的內(nèi)存都將在方法區(qū)中進(jìn)行分配共苛,這時(shí)候進(jìn)行內(nèi)存分配的僅包括類變量(被static修飾的變量)。其次蜓萄,這里所說的初始值“通常情況”下是數(shù)據(jù)類型的零值(null或零)隅茎。至于“特殊情況”是指:public static final int value=110,會直接初始化為指定的值 110嫉沽。

????????????1.2.3辟犀、解析階段是虛擬機(jī)將常量池內(nèi)的符號引用替換為直接引用的過程。解析動(dòng)作主要針對類或接口绸硕、字段堂竟、類方法、接口方法玻佩、方法類型出嘹、方法句柄和調(diào)用點(diǎn)限定符7類符號引用進(jìn)行。



? ? ? ?1.3咬崔、初始化階段

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

????????????<clinit>()方法是由編譯器自動(dòng)收集類中的所有類變量的賦值動(dòng)作和靜態(tài)語句塊static{}中的語句合并產(chǎn)生的疚漆,編譯器收集的順序是由語句在源文件中出現(xiàn)的順序所決定的,靜態(tài)語句塊只能訪問到定義在靜態(tài)語句塊之前的變量.????

????????????<clinit>()方法與實(shí)例構(gòu)造器<init>()方法不同,它不需要顯示地調(diào)用父類構(gòu)造器娶聘,虛擬機(jī)會保證在子類<clinit>()方法執(zhí)行之前闻镶,父類的<clinit>()方法方法已經(jīng)執(zhí)行完畢.

? ? ? ? ? ? tip:

????????????1.3.1、父類中定義的靜態(tài)語句塊要優(yōu)先于子類的變量賦值操作;

????????????1.3.2丸升、如果一個(gè)類或接口中沒有靜態(tài)語句塊铆农,也沒有對變量的賦值操作,那么編譯器可以不為這個(gè)類生成<clinit>()方法;

? ? ? ? ? ? 1.3.3狡耻、接口與類不同的是墩剖,執(zhí)行接口的<clinit>()方法不需要先執(zhí)行父接口的<clinit>()方法。只有當(dāng)父接口中定義的變量使用時(shí)夷狰,父接口才會初始化岭皂。另外,接口的實(shí)現(xiàn)類在初始化時(shí)也一樣不會執(zhí)行接口的()方法;

? ? ? ? ????1.3.4沼头、虛擬機(jī)會保證一個(gè)類的<clinit>()方法在多線程環(huán)境中被正確的加鎖爷绘、同步,如果多個(gè)線程同時(shí)去初始化一個(gè)類进倍,那么只會有一個(gè)線程去執(zhí)行這個(gè)類的<clinit>()方法土至,其他線程都需要阻塞等待,直到活動(dòng)線程執(zhí)行<clinit>()方法完畢猾昆。如果在一個(gè)類的<clinit>()方法中有好事很長的操作陶因,就可能造成多個(gè)線程阻塞,在實(shí)際應(yīng)用中這種阻塞往往是隱藏的垂蜗。


????????1.4楷扬、卸載階段

? ? ? ? ????虛擬機(jī)執(zhí)行卸載類需要滿足以下三個(gè)條件之一:

????????????1.4.1、 加載該類的ClassLoader已經(jīng)被回收贴见。?

????????????1.4.2烘苹、該類所有的實(shí)例都已經(jīng)被回收,也就是java堆中不存在該類的任何實(shí)例蝇刀。

????????????1.4.3螟加、該類對應(yīng)的java.lang.Class對象沒有任何地方被引用徘溢,無法在任何地方通過反射訪問該類的方法吞琐。


下面以一種問答方式進(jìn)一步了解加載機(jī)制:

????一、能簡單點(diǎn)描述什么是類加載嘛然爆?

? ? ????????應(yīng)該能站粟。類加載是:通過類加載裝載器ClassLoader將類的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi)曾雕,然后在堆區(qū)創(chuàng)建一個(gè)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)的接口揩环。?通過該class對象可以獲知Class的結(jié)構(gòu)信息:如構(gòu)造函數(shù),屬性和方法等

????二幅虑、類加載裝載器又是什么嘛丰滑?

????????????ClassLoader負(fù)責(zé)對類的加載,讀取 Java 字節(jié)代碼倒庵,并轉(zhuǎn)換成java.lang.Class類的一個(gè)實(shí)例褒墨,最后對該類進(jìn)行管理。

????三擎宝、可以深入點(diǎn)講解類加載器嘛郁妈?聽說有三種類型那么多呢。

????????????可以的绍申。java自身提供的確實(shí)有三種類型噩咪。其中包括了:

? ? ? ? ? ? 3.1、啟動(dòng)類加載器失晴,Bootstrap ClassLoader剧腻,加載\jre\lib\rt.jar,或者被-Xbootclasspath參數(shù)限定的類涂屁;

? ? ? ? ? ? 3.2书在、擴(kuò)展類加載器,Extension ClassLoader拆又,加載\jre\lib\ext儒旬,或者被java.ext.dirs系統(tǒng)變量指定的類;

? ? ? ? ? ? 3.3帖族、應(yīng)用程序類加載器栈源,Application ClassLoader,加載ClassPath中的類庫竖般;

? ? ? ? ? ? 當(dāng)然甚垦,javaer們還可以自定義類加載器,通過繼承ClassLoader實(shí)現(xiàn)涣雕,一般是加載我們的自定義類艰亮。

類加載器

????????????類加載器通過雙親委派模型,在每次收到類加載請求時(shí)挣郭,先將請求委派給父類加載器完成(所有加載請求最終會委派到頂層的Bootstrap ClassLoader加載器中)迄埃,如果父類加載器無法完成這個(gè)加載,子類再嘗試自己加載兑障。

????????四侄非、為什么要用雙親委派模型將請求發(fā)送給父類來處理呢蕉汪?

????????????????這個(gè)問的真是好。這種模式的存在必然有它的充分的理由逞怨。原因是:類加載器決定了類的唯一性者疤。意思是,同一份的字節(jié)代碼叠赦,被不同的類加載器加載之后宛渐,所得到的類是不同的。假設(shè)眯搭,我們不使用雙親委派模型窥翩,將請求交由父類處理,那么就是自身處理咯鳞仙。那在這個(gè)大前提下寇蚊,再假設(shè)我們定義兩個(gè)自定義加載類MyCLod1和MyCLod2,它們加載一個(gè)先生自己寫的類MyClass棍好。根據(jù)類加載器決定類的唯一性仗岸,那么在方法區(qū)中會出現(xiàn)兩份不一樣的類,那么后面我們該選擇那份來使用呢借笙?而當(dāng)將這個(gè)MyClass類統(tǒng)一交給父類加載扒怖,只存在一份類,即不存在選擇使用的情況业稼。同時(shí)盗痒,也避免同一個(gè)類被多次加載,占用內(nèi)存的情況低散。

????????五俯邓、準(zhǔn)備階段有類變量初始化、初始化階段也有對類變量的初始化熔号,兩者有什么不同嘛稽鞭?

????????????????前者是將類變量初始化位Java默認(rèn)值零或null,后者是初始化程序員設(shè)置的類變量邏輯初始值引镊。不一樣的朦蕴。

????????六、那初始化階段觸發(fā)條件是什么呢弟头?面霸經(jīng)常遇到這樣的問題呢吩抓。

????????????????觸發(fā)條件有6個(gè)那么多:

????????????????6.1、為一個(gè)類型創(chuàng)建一個(gè)新的對象實(shí)例時(shí)(比如new亮瓷、反射琴拧、序列化)降瞳;

? ? ? ? ? ? ? ? 6.2嘱支、調(diào)用一個(gè)類型的靜態(tài)方法時(shí)(即在字節(jié)碼中執(zhí)行invokestatic指令)蚓胸;

????????????????6.3、調(diào)用一個(gè)類型或接口的靜態(tài)字段除师,或者對這些靜態(tài)字段執(zhí)行賦值操作時(shí)(即在字節(jié)碼中沛膳,執(zhí)行g(shù)etstatic或者putstatic指令),不過用final修飾的靜態(tài)字段除外汛聚,它被初始化為一個(gè)編譯時(shí)常量表達(dá)式锹安;

? ? ? ? ? ? ????6.4、調(diào)用JavaAPI中的反射方法時(shí)(比如調(diào)用java.lang.Class中的方法倚舀,或者java.lang.reflect包中其他類的方法)叹哭;

? ? ? ? ? ? ? ? 6.5、初始化一個(gè)類的派生類時(shí)(Java虛擬機(jī)規(guī)范明確要求初始化一個(gè)類時(shí)痕貌,它的超類必須提前完成初始化操作风罩,接口例外);

? ? ? ? ? ? ? ? 6.6舵稠、JVM啟動(dòng)包含main方法的啟動(dòng)類時(shí)超升;

????????七、為什么需要類卸載階段哺徊?

? ? ? ? ? ? 不要說為什么提出這么幼稚的問題室琢,我之前還真沒認(rèn)真想過這個(gè)問題呢。要回答這個(gè)問題不得不落追,追溯到Java語言創(chuàng)建之初衷盈滴,為嵌入式應(yīng)用開發(fā)。當(dāng)時(shí)嵌入式機(jī)器普遍內(nèi)存小轿钠,不能讓已經(jīng)沒用的類再占用緊張的內(nèi)存雹熬,所以存在類卸載機(jī)制。

????????八谣膳、最后貼一段代碼竿报,嘿嘿嘿。就給圖继谚,不直接給代碼烈菌,自己手撕更容易理解結(jié)果輸出的原理。(關(guān)鍵提示:可以從靜態(tài)變量執(zhí)行循序著手)

手撕代碼圖



????我是先生花履,找尋著那位迷路的Miss芽世。最后,愿各位 javaer 诡壁,合上電腦的剎那济瓢,有著俠客收劍入鞘的驕傲!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末妹卿,一起剝皮案震驚了整個(gè)濱河市旺矾,隨后出現(xiàn)的幾起案子蔑鹦,更是在濱河造成了極大的恐慌,老刑警劉巖箕宙,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嚎朽,死亡現(xiàn)場離奇詭異,居然都是意外死亡柬帕,警方通過查閱死者的電腦和手機(jī)哟忍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陷寝,“玉大人锅很,你說我怎么就攤上這事》锱埽” “怎么了粗蔚?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長饶火。 經(jīng)常有香客問我鹏控,道長,這世上最難降的妖魔是什么肤寝? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任当辐,我火速辦了婚禮,結(jié)果婚禮上鲤看,老公的妹妹穿的比我還像新娘缘揪。我一直安慰自己,他們只是感情好义桂,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布找筝。 她就那樣靜靜地躺著,像睡著了一般慷吊。 火紅的嫁衣襯著肌膚如雪袖裕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天溉瓶,我揣著相機(jī)與錄音急鳄,去河邊找鬼。 笑死堰酿,一個(gè)胖子當(dāng)著我的面吹牛疾宏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播触创,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼坎藐,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了哼绑?” 一聲冷哼從身側(cè)響起岩馍,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤碉咆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后兼雄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡帽蝶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年赦肋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片励稳。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡佃乘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出驹尼,到底是詐尸還是另有隱情趣避,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布新翎,位于F島的核電站程帕,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏地啰。R本人自食惡果不足惜愁拭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望亏吝。 院中可真熱鬧岭埠,春花似錦、人聲如沸蔚鸥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽止喷。三九已至馆类,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間弹谁,已是汗流浹背蹦掐。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留僵闯,地道東北人卧抗。 一個(gè)月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像鳖粟,于是被迫代替她去往敵國和親社裆。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359

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