虛擬機字節(jié)碼執(zhí)行引擎

在Java虛擬機規(guī)范中制定了虛擬機字節(jié)碼執(zhí)行引擎的概念模型,這個概念模型成為各種虛擬機的統(tǒng)一外觀莱找。從外觀來看酬姆,所有的Java虛擬機的執(zhí)行引擎都是一致的:輸入的是字節(jié)碼文件,處理過程是字節(jié)碼解析的等效過程奥溺,輸出的是執(zhí)行結(jié)果辞色。

運行時棧幀結(jié)構(gòu)

????棧幀是用于支持虛擬機進行方法調(diào)用和方法執(zhí)行的數(shù)據(jù)結(jié)構(gòu),它是虛擬機運行時數(shù)據(jù)區(qū)中的虛擬機棧的棧元素浮定。棧幀存儲了方法的局部變量表相满、操作數(shù)棧、動態(tài)連接和方法返回地址等信息桦卒。每一個方法從調(diào)用開始至執(zhí)行完成的過程立美,都對應(yīng)著一個棧幀在虛擬機棧里面從入棧到出棧的過程。

? ? 每一個棧幀都包括了局部變量表方灾、操作數(shù)棧建蹄、動態(tài)鏈接、方法返回地址和一些額外的附加信息裕偿。在編譯程序代碼的時候洞慎,棧幀中需要多大的局部變量表,多深的操作數(shù)棧都已經(jīng)完全確定了嘿棘,并且寫入到方法表的Code屬性之中劲腿,因此一個棧幀需要分配多少內(nèi)存,不會受到程序運行期變量數(shù)據(jù)的影響鸟妙,而僅僅取決于具體的虛擬機實現(xiàn)焦人。一個線程中的方法調(diào)用鏈可能會很長,很多方法都同時處于執(zhí)行狀態(tài)重父。對于執(zhí)行引擎來說花椭,在活動線程中,只有位于棧頂?shù)臈攀怯行У钠汗Q為當(dāng)前棧幀个从,與這個棧幀相關(guān)聯(lián)的方法稱為當(dāng)前方法,執(zhí)行引擎運行的所有字節(jié)碼指令都只針對當(dāng)前棧幀進行操作歪沃。


局部變量表

????局部變量表是一組變量值存儲空間嗦锐,用于存放方法參數(shù)和方法內(nèi)部定義的局部變量。在Java程序時沪曙,就在方法的Code屬性的max_locals數(shù)據(jù)項中確定了該方法所需要分配的局部變量表的最大容量奕污。

? ? 局部變量表的容量以變量槽(Slot)為最小單位,一個Slot應(yīng)該能存放一個boolean液走、byte碳默、char贾陷、short、int嘱根、float髓废、reference或returnAddress類型的數(shù)據(jù),這八種數(shù)據(jù)類型该抒。對于64位的數(shù)據(jù)類型慌洪,虛擬機會以高位對其的方式為其分配兩個連續(xù)的Slot空間。Java語言中明確的64位的數(shù)據(jù)類型只有l(wèi)ong和double兩種凑保。這里把long和double數(shù)據(jù)類型分割存儲的做法與“l(fā)ong和double的非原子性協(xié)定”中把一次long和double數(shù)據(jù)類型讀寫分割為兩次32位讀寫的做法有些類似冈爹。

為了盡可能節(jié)省棧幀空間,局部變量表中的Slot是可以重用的欧引,方法體中定義的變量其作用域并不一定會覆蓋整個方法體频伤,如果當(dāng)前字節(jié)碼PC計數(shù)器的值已經(jīng)超出了某個變量的作用域,那這個變量對應(yīng)的Slot就可以交給其他變量使用芝此。不過憋肖,這樣的設(shè)計除了節(jié)省棧幀空間以外,還會伴隨一些額外的副作用婚苹,例如會影響系統(tǒng)的垃圾收集行為瞬哼。原因大致是局部變量表中還有關(guān)于對象的引用作為GC Roots存在。


操作數(shù)棧

操作數(shù)棧是一個后入先出的棧租副。同局部變量一樣,操作數(shù)棧的最大深度也在編譯的時候?qū)懭氲紺ode屬性的max_stacks數(shù)據(jù)項中较性。操作數(shù)棧的每一個元素可以是任意的Java數(shù)據(jù)類型用僧,包括long和double。32位數(shù)據(jù)類型所占的棧容量為1从撼,64位數(shù)據(jù)類型所占的棧容量為2颊亮。在方法執(zhí)行的任何時候歌粥,操作數(shù)棧的深度都不會超過在max_stacks數(shù)據(jù)項中設(shè)定的最大值。

當(dāng)一個方法剛剛開始執(zhí)行的時候院仿,這個方法的操作數(shù)棧是空的,在方法的執(zhí)行過程中速和,會有各種字節(jié)碼指令往操作數(shù)棧中寫入和提取內(nèi)容歹垫,也就是出棧/入棧操作。例如颠放,在做算術(shù)運算的時候是通過操作數(shù)棧來進行的排惨,又或者在調(diào)用其他方法的時候是通過操作數(shù)棧來進行參數(shù)傳遞的。

舉個例子碰凶,整數(shù)加法的字節(jié)碼指令iadd在運行的時候操作數(shù)棧中最接近棧頂?shù)膬蓚€元素已經(jīng)存入了兩個int型的數(shù)值暮芭,當(dāng)執(zhí)行這個指令時鹿驼,會將這兩個int值出棧并相加,然后將相加的結(jié)果入棧辕宏。

操作數(shù)棧中元素的數(shù)據(jù)類型必須與字節(jié)碼指令的序列嚴格匹配畜晰,在編譯程序代碼的時候,編譯器要嚴格保證這一點瑞筐,在類校驗階段的數(shù)據(jù)流分析中還要再次驗證這一點凄鼻。再以上面的iadd指令為例,這個指令用于整型數(shù)加法面哼,它在執(zhí)行時野宜,最接近棧頂?shù)膬蓚€元素的數(shù)據(jù)類型必須為int型,不能出現(xiàn)一個long和一個float使用iadd命令相加的情況魔策。


動態(tài)連接

每個棧幀都包含一個指向運行時常量池中該棧幀所屬方法的引用匈子,持有這個引用是為了支持方法調(diào)用過程中的動態(tài)連接。Class文件的常量池中存有大量的符號引用闯袒,字節(jié)碼中的方法調(diào)用指令就以常量池中指向方法的符號引用作為參數(shù)虎敦。這些符號引用一部分會在類加載階段或者第一次使用的時候就轉(zhuǎn)化為直接引用,這種轉(zhuǎn)化稱為靜態(tài)解析政敢。另外一部分將在每一次運行期間轉(zhuǎn)化為直接引用其徙,這部分稱為動態(tài)連接。


方法返回地址

當(dāng)一個方法開始執(zhí)行后喷户,只有兩種方式可以退出這個方法唾那。第一種方式是執(zhí)行引擎遇到任意一個方法返回的字節(jié)碼指令,這時候可能會有返回值傳遞給上層的方法調(diào)用者褪尝,是否有返回值和返回值的類型將根據(jù)遇到何種方法返回指令來決定闹获,這種退出方法稱為正常完成出口。

另一種退出方式是河哑,在方法執(zhí)行過程中遇到了異常避诽,并且這個異常沒有在方法體內(nèi)得到處理,無論是Java虛擬機內(nèi)部產(chǎn)生的異常璃谨,還是代碼中使用athrow字節(jié)碼指令產(chǎn)生的異常沙庐,只要在本方法的異常表中沒有搜索到匹配的異常處理器,就會導(dǎo)致方法退出佳吞,這種退出方法的方式稱為異常完成出口拱雏。一個方法使用異常完成出口的方式退出,是不會給它的上層調(diào)用者產(chǎn)生任何返回值的容达。

無論采用何種退出方式古涧,在方法退出之后,都需要返回到方法被調(diào)用的位置花盐,程序才能繼續(xù)執(zhí)行羡滑,方法返回時可能需要在棧幀中保存一些信息菇爪,用來幫助恢復(fù)它的上層方法的執(zhí)行狀態(tài)。一般來說柒昏,方法正常退出時凳宙,調(diào)用者的PC計數(shù)器的值可以作為返回地址,棧幀中很可能會保存這個計數(shù)器值职祷。而方法異常退出時氏涩,返回地址是要通過異常處理器表來確定的,棧幀中一般不會保存這部分信息有梆。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末是尖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子泥耀,更是在濱河造成了極大的恐慌饺汹,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件痰催,死亡現(xiàn)場離奇詭異兜辞,居然都是意外死亡,警方通過查閱死者的電腦和手機夸溶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門逸吵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人缝裁,你說我怎么就攤上這事扫皱。” “怎么了捷绑?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵啸罢,是天一觀的道長。 經(jīng)常有香客問我胎食,道長,這世上最難降的妖魔是什么允懂? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任厕怜,我火速辦了婚禮,結(jié)果婚禮上蕾总,老公的妹妹穿的比我還像新娘粥航。我一直安慰自己,他們只是感情好生百,可當(dāng)我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布递雀。 她就那樣靜靜地躺著,像睡著了一般蚀浆。 火紅的嫁衣襯著肌膚如雪缀程。 梳的紋絲不亂的頭發(fā)上搜吧,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天,我揣著相機與錄音杨凑,去河邊找鬼滤奈。 笑死,一個胖子當(dāng)著我的面吹牛撩满,可吹牛的內(nèi)容都是我干的蜒程。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼伺帘,長吁一口氣:“原來是場噩夢啊……” “哼昭躺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起伪嫁,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤领炫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后礼殊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驹吮,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年晶伦,在試婚紗的時候發(fā)現(xiàn)自己被綠了碟狞。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡婚陪,死狀恐怖族沃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情泌参,我是刑警寧澤脆淹,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站沽一,受9級特大地震影響盖溺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜铣缠,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一烘嘱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蝗蛙,春花似錦蝇庭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至壮韭,卻和暖如春北发,著一層夾襖步出監(jiān)牢的瞬間纹因,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工鲫竞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留辐怕,地道東北人。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓从绘,卻偏偏與公主長得像寄疏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子僵井,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,630評論 2 359

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