JVM Java文件運(yùn)行全流程及類加載機(jī)制

一涌乳、java文件運(yùn)行的全部過(guò)程是怎么樣的呢布疼?

image.png

當(dāng)一個(gè)classLoder啟動(dòng)的時(shí)候燕锥,classLoader的生存地點(diǎn)在jvm中的堆赚楚,然后它會(huì)去主機(jī)硬盤上將A.class裝載到j(luò)vm的方法區(qū)淌友,方法區(qū)中的這個(gè)字節(jié)文件會(huì)被虛擬機(jī)拿來(lái)new A字節(jié)碼()煌恢,然后在堆內(nèi)存生成了一個(gè)A字節(jié)碼的對(duì)象,然后A字節(jié)碼這個(gè)內(nèi)存文件有兩個(gè)引用一個(gè)指向A的class對(duì)象震庭,一個(gè)指向加載自己的classLoader

java虛擬機(jī)的生命周期:聲明周期起點(diǎn)是當(dāng)一個(gè)java應(yīng)用main函數(shù)啟動(dòng)時(shí)虛擬機(jī)也同時(shí)被啟動(dòng)瑰抵,而只有當(dāng)在虛擬機(jī)實(shí)例中的所有非守護(hù)進(jìn)程都結(jié)束時(shí),java虛擬機(jī)實(shí)例才結(jié)束生命器联。
java的虛擬機(jī)種有兩種線程二汛,一種叫叫守護(hù)線程婿崭,一種叫非守護(hù)線程(也叫普通線程),main函數(shù)就是個(gè)非守護(hù)線程肴颊,虛擬機(jī)的gc就是一個(gè)守護(hù)線程氓栈。java的虛擬機(jī)中,只要有任何非守護(hù)線程還沒(méi)有結(jié)束婿着,java虛擬機(jī)的實(shí)例都不會(huì)退出授瘦,所以即使main函數(shù)這個(gè)非守護(hù)線程退出,但是由于在main函數(shù)中啟動(dòng)的匿名線程也是非守護(hù)線程竟宋,它還沒(méi)有結(jié)束提完,所以jvm沒(méi)辦法退出

java源文件到最后運(yùn)行起來(lái),主要會(huì)經(jīng)過(guò)兩個(gè)階段:

1丘侠、.java文件通過(guò)java編譯器(javac.exe)編譯成.class文件氯葬,這個(gè)就是所說(shuō)的字節(jié)碼文件。

2婉陷、.class文件加載到j(luò)vm進(jìn)行運(yùn)行

image

首先帚称,當(dāng)一個(gè)程序啟動(dòng)之前,它的class會(huì)被類裝載器裝入方法區(qū)(不好聽(tīng)秽澳,其實(shí)這個(gè)區(qū)我喜歡叫做Permanent區(qū))闯睹,執(zhí)行引擎讀取方法區(qū)的字節(jié)碼自適應(yīng)解析,邊解析就邊運(yùn)行(其中一種方式)担神,然后pc寄存器指向了main函數(shù)所在位置楼吃,虛擬機(jī)開(kāi)始為main函數(shù)在java棧中預(yù)留一個(gè)棧幀(每個(gè)方法都對(duì)應(yīng)一個(gè)棧幀),然后開(kāi)始跑main函數(shù)妄讯,main函數(shù)里的代碼被執(zhí)行引擎映射成本地操作系統(tǒng)里相應(yīng)的實(shí)現(xiàn)孩锡,然后調(diào)用本地方法接口,本地方法運(yùn)行的時(shí)候亥贸,操縱系統(tǒng)會(huì)為本地方法分配本地方法棧躬窜,用來(lái)儲(chǔ)存一些臨時(shí)變量,然后運(yùn)行本地方法炕置,調(diào)用操作系統(tǒng)APIi等等荣挨。

jvm內(nèi)部執(zhí)行運(yùn)行流程圖:

這里寫圖片描述

JVM運(yùn)行簡(jiǎn)易過(guò)程:

image.png

上圖左半部分其實(shí)不是在JVM中,程序員在eclipse上寫的是.java文件朴摊,經(jīng)過(guò)編譯成.class文件(比如maven工程需要maven install默垄,打成jar報(bào),jar包里面都是.calss文件)甚纲;這些步驟都是在eclipse上進(jìn)行的口锭。然后類加載器(classloader)一直到解釋器是屬于JVM的

二、JVM是如何來(lái)處理.class文件的

首先來(lái)分析下JVM到底是個(gè)怎么樣的東西

image

JVM被分為三個(gè)主要的子系統(tǒng)

(1)類加載器子系統(tǒng)(2)運(yùn)行時(shí)數(shù)據(jù)區(qū)(3)執(zhí)行引擎

1. 類加載器子系統(tǒng)

image

加載介杆、驗(yàn)證鹃操、準(zhǔn)備和初始化這四個(gè)階段發(fā)生的順序是確定的况既,而解析階段則不一定,它在某些情況下可以在初始化階段之后開(kāi)始组民,這是為了支持Java語(yǔ)言的運(yùn)行時(shí)綁定(也成為動(dòng)態(tài)綁定或晚期綁定)棒仍。另外注意這里的幾個(gè)階段是按順序開(kāi)始,而不是按順序進(jìn)行或完成臭胜,因?yàn)檫@些階段通常都是互相交叉地混合進(jìn)行的莫其,通常在一個(gè)階段執(zhí)行的過(guò)程中調(diào)用或激活另一個(gè)階段。

?加載

jvm系列(一):java類的加載機(jī)制 - 純潔的微笑 - 博客園?www.cnblogs.com

加載是類加載過(guò)程的第一個(gè)階段耸三,在加載階段乱陡,虛擬機(jī)需要完成以下三件事情:

① 通過(guò)一個(gè)類的全限定名來(lái)獲取其定義的二進(jìn)制字節(jié)流。
② 將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)仪壮。
③ 在Java堆中生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象憨颠,作為對(duì)方法區(qū)中這些數(shù)據(jù)的訪問(wèn)入口。

相對(duì)于類加載的其他階段而言积锅,加載階段(準(zhǔn)確地說(shuō)爽彤,是加載階段獲取類的二進(jìn)制字節(jié)流的動(dòng)作)是可控性最強(qiáng)的階段,因?yàn)殚_(kāi)發(fā)人員既可以使用系統(tǒng)提供的類加載器來(lái)完成加載缚陷,也可以自定義自己的類加載器來(lái)完成加載适篙。

加載階段完成后,虛擬機(jī)外部的 二進(jìn)制字節(jié)流就按照虛擬機(jī)所需的格式存儲(chǔ)在方法區(qū)之中箫爷,而且在Java堆中也創(chuàng)建一個(gè)java.lang.Class類的對(duì)象嚷节,這樣便可以通過(guò)該對(duì)象訪問(wèn)方法區(qū)中的這些數(shù)據(jù)。

?連接

1)驗(yàn)證:確保被加載的類的正確性

驗(yàn)證是連接階段的第一步虎锚,這一階段的目的是為了確保Class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求硫痰,并且不會(huì)危害虛擬機(jī)自身的安全。驗(yàn)證階段大致會(huì)完成4個(gè)階段的檢驗(yàn)動(dòng)作:

文件格式驗(yàn)證:驗(yàn)證字節(jié)流是否符合Class文件格式的規(guī)范窜护;例如:是否以0xCAFEBABE開(kāi)頭效斑、主次版本號(hào)是否在當(dāng)前虛擬機(jī)的處理范圍之內(nèi)、常量池中的常量是否有不被支持的類型柄慰。
元數(shù)據(jù)驗(yàn)證:對(duì)字節(jié)碼描述的信息進(jìn)行語(yǔ)義分析(注意:對(duì)比javac編譯階段的語(yǔ)義分析)鳍悠,以保證其描述的信息符合Java語(yǔ)言規(guī)范的要求税娜;例如:這個(gè)類是否有父類坐搔,除了java.lang.Object之外。
字節(jié)碼驗(yàn)證:通過(guò)數(shù)據(jù)流和控制流分析敬矩,確定程序語(yǔ)義是合法的概行、符合邏輯的。
符號(hào)引用驗(yàn)證:確保解析動(dòng)作能正確執(zhí)行弧岳。

驗(yàn)證階段是非常重要的凳忙,但不是必須的业踏,它對(duì)程序運(yùn)行期沒(méi)有影響,如果所引用的類經(jīng)過(guò)反復(fù)驗(yàn)證涧卵,那么可以考慮采用-Xverifynone參數(shù)來(lái)關(guān)閉大部分的類驗(yàn)證措施勤家,以縮短虛擬機(jī)類加載的時(shí)間。

2)準(zhǔn)備:為類的靜態(tài)變量分配內(nèi)存柳恐,并將其初始化為默認(rèn)值

準(zhǔn)備階段是正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段伐脖,這些內(nèi)存都將在方法區(qū)中分配。對(duì)于該階段有以下幾點(diǎn)需要注意:

① 這時(shí)候進(jìn)行內(nèi)存分配的僅包括類變量(static)乐设,而不包括實(shí)例變量讼庇,實(shí)例變量會(huì)在對(duì)象實(shí)例化時(shí)隨著對(duì)象一塊分配在Java堆中。
② 這里所設(shè)置的初始值通常情況下是數(shù)據(jù)類型默認(rèn)的零值(如0近尚、0L蠕啄、null、false等)戈锻,而不是被在Java代碼中被顯式地賦予的值歼跟。

假設(shè)一個(gè)類變量的定義為:public static int value = 3;

那么變量value在準(zhǔn)備階段過(guò)后的初始值為0格遭,而不是3嘹承,因?yàn)檫@時(shí)候尚未開(kāi)始執(zhí)行任何Java方法,而把value賦值為3的putstatic指令是在程序編譯后如庭,存放于類構(gòu)造器<clinit>()方法之中的叹卷,所以把value賦值為3的動(dòng)作將在初始化階段才會(huì)執(zhí)行

3)解析:把類中的符號(hào)引用轉(zhuǎn)換為直接引用

解析階段是虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過(guò)程,解析動(dòng)作主要針對(duì)類或接口坪它、字段骤竹、類方法、接口方法往毡、方法類型蒙揣、方法句柄和調(diào)用點(diǎn)限定符7類符號(hào)引用進(jìn)行。符號(hào)引用就是一組符號(hào)來(lái)描述目標(biāo)开瞭,可以是任何字面量懒震。

直接引用就是直接指向目標(biāo)的指針、相對(duì)偏移量或一個(gè)間接定位到目標(biāo)的句柄嗤详。

  • 初始化

類初始化階段是類加載的最后一步个扰,前面的類加載過(guò)程中,除了在加載階段用戶用程序可以通過(guò)自定義類加載器參與之外葱色,其余動(dòng)作完全由虛擬機(jī)主導(dǎo)和控制递宅。到了初始化階段,才真正開(kāi)始執(zhí)行類中定義的Java程序代碼(或者說(shuō)字節(jié)碼)。這里所有的靜態(tài)變量會(huì)被賦初始值, 并且靜態(tài)塊將被執(zhí)行办龄。

java中烘绽,對(duì)于初始化階段,有且只有以下五種情況才會(huì)對(duì)要求類立刻初始化:

① 使用new關(guān)鍵字實(shí)例化對(duì)象俐填、訪問(wèn)或者設(shè)置一個(gè)類的靜態(tài)字段(被final修飾安接、編譯器優(yōu)化時(shí)已經(jīng)放入常量池的例外)、調(diào)用類方法英融,都會(huì)初始化該靜態(tài)字段或者靜態(tài)方法所在的類赫段;
② 初始化類的時(shí)候,如果其父類沒(méi)有被初始化過(guò)矢赁,則要先觸發(fā)其父類初始化糯笙;
③ 使用java.lang.reflect包的方法進(jìn)行反射調(diào)用的時(shí)候,如果類沒(méi)有被初始化撩银,則要先初始化给涕;
④ 虛擬機(jī)啟動(dòng)時(shí),用戶會(huì)先初始化要執(zhí)行的主類(含有main)额获;
⑤ jdk 1.7后够庙,如果java.lang.invoke.MethodHandle的實(shí)例最后對(duì)應(yīng)的解析結(jié)果是 REF_getStatic、REF_putStatic抄邀、REF_invokeStatic方法句柄耘眨,并且這個(gè)方法所在類沒(méi)有初始化,則先初始化境肾;

2剔难、運(yùn)行時(shí)數(shù)據(jù)

運(yùn)行時(shí)數(shù)據(jù)區(qū)域被劃分為5個(gè)主要組件:

① 方法區(qū) (線程共享) 常量 靜態(tài)變量 JIT(即時(shí)編譯器)編譯后代碼也在方法區(qū)存放
② 堆內(nèi)存(線程共享) 垃圾回收的主要場(chǎng)地
③ 程序計(jì)數(shù)器 當(dāng)前線程執(zhí)行的字節(jié)碼的位置指示器
④ Java虛擬機(jī)棧(棧內(nèi)存) :保存局部變量,基本數(shù)據(jù)類型以及堆內(nèi)存中對(duì)象的引用變量
⑤ 本地方法棧 (C棧):為JVM提供使用native方法的服務(wù)

image

3、執(zhí)行引擎

分配給運(yùn)行時(shí)數(shù)據(jù)區(qū)的字節(jié)碼將由執(zhí)行引擎執(zhí)行奥喻。執(zhí)行引擎讀取字節(jié)碼并逐段執(zhí)行偶宫。

① 解釋器: 解釋器能快速的解釋字節(jié)碼,但執(zhí)行卻很慢环鲤。 解釋器的缺點(diǎn)就是,當(dāng)一個(gè)方法被調(diào)用多次纯趋,每次都需要重新解釋。

② 即時(shí)(Just-In-Time)編譯器:JIT編譯器消除了解釋器的缺點(diǎn)冷离。執(zhí)行引擎利用解釋器轉(zhuǎn)換字節(jié)碼明也,但如果是重復(fù)的代碼則使用JIT編譯器將全部字節(jié)碼編譯成本機(jī)代碼倡鲸。
簡(jiǎn)單理解JIT就是當(dāng)代碼中某些方法復(fù)用次數(shù)比較高的规揪,并超過(guò)一個(gè)特定的值就成為了“熱點(diǎn)代碼”犯眠。那么這個(gè)這些熱點(diǎn)代碼就會(huì)被編譯成本地代碼(其實(shí)可以理解成緩存)加快訪問(wèn)速度甫菠。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末膨处,一起剝皮案震驚了整個(gè)濱河市解幼,隨后出現(xiàn)的幾起案子外永,更是在濱河造成了極大的恐慌留夜,老刑警劉巖匙铡,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件图甜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鳖眼,警方通過(guò)查閱死者的電腦和手機(jī)黑毅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)钦讳,“玉大人矿瘦,你說(shuō)我怎么就攤上這事≡缸洌” “怎么了缚去?”我有些...
    開(kāi)封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)琼开。 經(jīng)常有香客問(wèn)我易结,道長(zhǎng),這世上最難降的妖魔是什么柜候? 我笑而不...
    開(kāi)封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任搞动,我火速辦了婚禮,結(jié)果婚禮上渣刷,老公的妹妹穿的比我還像新娘鹦肿。我一直安慰自己,他們只是感情好辅柴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布箩溃。 她就那樣靜靜地躺著,像睡著了一般碌嘀。 火紅的嫁衣襯著肌膚如雪碾篡。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天筏餐,我揣著相機(jī)與錄音开泽,去河邊找鬼。 笑死魁瞪,一個(gè)胖子當(dāng)著我的面吹牛穆律,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播导俘,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼峦耘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了旅薄?” 一聲冷哼從身側(cè)響起辅髓,我...
    開(kāi)封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤泣崩,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后洛口,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體矫付,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年第焰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了买优。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡挺举,死狀恐怖杀赢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情湘纵,我是刑警寧澤脂崔,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站梧喷,受9級(jí)特大地震影響砌左,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜伤柄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一绊困、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧适刀,春花似錦秤朗、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至常挚,卻和暖如春作谭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奄毡。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工折欠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吼过。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓锐秦,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親盗忱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子酱床,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

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