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

"虛擬機(jī)"是相對(duì)于"物理機(jī)"的概念,這兩種機(jī)器都有執(zhí)行代碼能力乍炉,其區(qū)別是物理機(jī)的執(zhí)行引擎是直接建立在處理器绢片、硬件、指令集和操作系統(tǒng)層面上的岛琼,而虛擬機(jī)的執(zhí)行引擎則是由自己實(shí)現(xiàn)的底循,因此可以自行制定指令集與執(zhí)行引擎的結(jié)構(gòu)體系,并且能夠執(zhí)行哪些不被硬件直接支持的指令集格式槐瑞。在不同的虛擬機(jī)實(shí)現(xiàn)里面熙涤,執(zhí)行引擎在執(zhí)行Java代碼的時(shí)候可能會(huì)有解釋執(zhí)行(通過(guò)解釋器執(zhí)行)和編譯執(zhí)行(通過(guò)即時(shí)編譯器產(chǎn)生本地代碼執(zhí)行)兩種選擇,也可能兩者兼?zhèn)洌踔吝€可能會(huì)包含幾個(gè)不同級(jí)別的編譯器執(zhí)行引擎祠挫,但從外觀上看起來(lái)猬错,所有的Java虛擬機(jī)的執(zhí)行引擎都是一致的:輸入的是字節(jié)碼文件,處理過(guò)程是字節(jié)碼解析的等效過(guò)程茸歧,輸出的是執(zhí)行結(jié)果倦炒。

運(yùn)行時(shí)棧幀結(jié)構(gòu)

棧幀(Statck Frame)是用于支持虛擬機(jī)進(jìn)行方法調(diào)用和方法執(zhí)行的數(shù)據(jù)結(jié)構(gòu),它是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)中的虛擬機(jī)棧(Virtual Machine Stack)的棧元素软瞎。棧幀存儲(chǔ)了方法的局部變量表逢唤、操作數(shù)棧、動(dòng)態(tài)連接和方法返回地址等信息涤浇。每一個(gè)方法從調(diào)用開(kāi)始至執(zhí)行完成的過(guò)程鳖藕,都是對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧里面從入棧到出棧的過(guò)程。 一個(gè)線程中的方法調(diào)用鏈可能會(huì)很長(zhǎng)只锭,很多方法都同事對(duì)處于執(zhí)行狀態(tài)著恩。但對(duì)于執(zhí)行引擎來(lái)說(shuō),在活動(dòng)線程中蜻展,只有位于棧頂?shù)臈攀怯行У暮硖埽Q為當(dāng)前棧幀(Current Stack Frame),與這個(gè)棧幀相關(guān)聯(lián)的方法稱為當(dāng)前方法(Current Method)纵顾。?


局部變量表

局部變量表(Local Variable Table)是一組變值存儲(chǔ)空間伍茄,用于存放方法參數(shù)和方法內(nèi)部定義的局部變量。在Java程序編譯為Class文件時(shí)施逾,就在放的Code屬性的max_locals數(shù)據(jù)項(xiàng)中確定了該方法所需要分配的局部變量表的最大容量敷矫。 局部變量表的容量以變量槽(Variable Slot)為最小單位。每個(gè)Slot都應(yīng)該能存放一個(gè)boolean汉额、byte曹仗、char、short蠕搜、int怎茫、float、reference讥脐、或returnAddress類(lèi)型的數(shù)據(jù)遭居,這8種數(shù)據(jù)類(lèi)型,都可以使用32位或更小的物理內(nèi)存來(lái)存放旬渠。Slot的長(zhǎng)度可以隨著處理器俱萍、操作系統(tǒng)或虛擬機(jī)的不同而發(fā)生變化。

reference類(lèi)型

reference類(lèi)型類(lèi)型表示對(duì)一個(gè)對(duì)象實(shí)例的引用告丢。虛擬機(jī)規(guī)范既沒(méi)有說(shuō)明它的長(zhǎng)度枪蘑,也沒(méi)有明確指出這種引用應(yīng)有怎樣的結(jié)構(gòu)。但一般說(shuō)來(lái),虛擬機(jī)實(shí)現(xiàn)至少都是通過(guò)這個(gè)引用做到兩點(diǎn)岳颇,一是從此引用中直接或間接地查到對(duì)象在Java堆中的數(shù)據(jù)存放地址索引照捡,二是引用中直接或間接地查找到對(duì)象所屬數(shù)據(jù)類(lèi)型在方法區(qū)中的存儲(chǔ)的類(lèi)型信息,否則無(wú)法實(shí)現(xiàn)Java語(yǔ)言規(guī)范中定義的語(yǔ)法約束话侧。

64位數(shù)據(jù)類(lèi)型(long栗精、double)

對(duì)于64位的數(shù)據(jù)類(lèi)型,虛擬機(jī)以高位對(duì)齊的方式為其分配兩個(gè)連續(xù)的Slot空間瞻鹏。Java語(yǔ)言中明確的(reference類(lèi)型則可能是32位也可能是64位)64位的數(shù)據(jù)類(lèi)型只有l(wèi)ong和double兩種悲立。由于局部變量表建立在線程的堆棧上,是線程私有的數(shù)據(jù)新博,無(wú)論讀寫(xiě)兩個(gè)連續(xù)的Slot是否為原子操作薪夕,都不會(huì)引起數(shù)據(jù)安全問(wèn)題。

Slot的訪問(wèn)方式

虛擬機(jī)通過(guò)索引定位的方式使用局部變量表赫悄,索引值的范圍從0開(kāi)始至局部變量表最大的Slot數(shù)量原献。如果訪問(wèn)的是32位數(shù)據(jù)類(lèi)型的變量,索引n就代表了使用第幾個(gè)Slot埂淮,如果是64位數(shù)據(jù)類(lèi)型的變量姑隅,則說(shuō)明會(huì)同時(shí)使用n和n+1兩個(gè)Slot。對(duì)于兩個(gè)相鄰的共同存放一個(gè)64位數(shù)據(jù)的兩個(gè)Slot同诫,不允許采用任何方式單獨(dú)訪問(wèn)其中的某一個(gè)粤策。

局部變量表Slot的復(fù)用


在上述代碼中,placeholder能否被回收的根本原因是:局部變量表中的Slot是否還存在有關(guān)于placeholder數(shù)組的引用误窖。第一次修改中,代碼雖然已經(jīng)離開(kāi)了placeholder的作用域秩贰,但在此之后霹俺,沒(méi)有任何對(duì)局部變量表的讀寫(xiě)操作,placeholder原本所占用的Slot還沒(méi)有被其他變量所復(fù)用毒费,所以作為GC Roots一部分的局部變量表仍然保持著對(duì)它的關(guān)聯(lián)丙唧。

關(guān)于局部變量表,還有一點(diǎn)可能對(duì)世紀(jì)開(kāi)發(fā)產(chǎn)生影響觅玻,就是局部變量不像前面介紹的類(lèi)變量那樣存在“準(zhǔn)備階段”想际。類(lèi)變量有兩次賦初始值的過(guò)程,一次在準(zhǔn)備階段溪厘,賦予系統(tǒng)初始值胡本;另一次在初始化階段,賦予程序員定義的初始值畸悬。但局部變量就不一樣侧甫,如果一個(gè)局部變量定義了但沒(méi)有賦初始值是不能使用的。

操作數(shù)棧

操作數(shù)棧(Operand Stack)也常稱為操作棧,它是一個(gè)后入先出(Last In First Out披粟,LIFO)棧咒锻。同局部變量表一樣,操作數(shù)棧的最大深度也在編譯的時(shí)候?qū)懭氲搅薈ode屬性的max_stacks數(shù)據(jù)項(xiàng)中守屉。操作數(shù)棧的每一個(gè)元素可以是任意的Java數(shù)據(jù)類(lèi)型惑艇,包括long和double。32位數(shù)據(jù)類(lèi)型所占的棧容量為1拇泛,64位數(shù)據(jù)類(lèi)型所占的棧容量為2敦捧。在方法執(zhí)行的任何時(shí)候,操作數(shù)棧的深度都不會(huì)超過(guò)在max_stacks數(shù)據(jù)項(xiàng)中設(shè)定的最大值碰镜。

工作原理

當(dāng)一個(gè)方法剛剛開(kāi)始執(zhí)行的時(shí)候兢卵,這個(gè)方法的操作數(shù)棧是空的,在方法的執(zhí)行過(guò)程中绪颖,會(huì)有各種字節(jié)碼指令往操作數(shù)棧中寫(xiě)入和提取內(nèi)容秽荤,也就是出棧/入棧操作。


動(dòng)態(tài)連接

每個(gè)棧幀都包含一個(gè)指向運(yùn)行時(shí)常量池中該棧幀所屬方法的引用柠横,持有這個(gè)引用是為了支持方法調(diào)用過(guò)程中的動(dòng)態(tài)連接(Dynamic Linking)窃款。

方法返回地址

當(dāng)一個(gè)方法開(kāi)始執(zhí)行后,只有兩種方式可以退出這個(gè)方法牍氛。第一種是執(zhí)行引擎遇到任意一個(gè)方法返回的字節(jié)碼指令(_return),這時(shí)候可能會(huì)有返回值傳遞給上層的方法調(diào)用者晨继,是否有返回值和返回值類(lèi)型將根據(jù)遇到何種方法返回指令來(lái)決定,這種退出方法的方式正常完成出口(Normal Method Invocation Completion)

另一種退出方式是搬俊,在方法執(zhí)行過(guò)程中遇到了異常紊扬,并且這個(gè)異常沒(méi)有在方法體內(nèi)得到處理,無(wú)論是Java虛擬機(jī)內(nèi)部產(chǎn)生的異常唉擂,還是代碼中使用athrow字節(jié)碼指令產(chǎn)生的異常餐屎,只要在本方法的異常表中沒(méi)有搜索到匹配的異常處理器,就會(huì)導(dǎo)致方法退出玩祟,這種退出方式稱為異常完成出口(Abrupt Method Invocation Completion)腹缩。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市空扎,隨后出現(xiàn)的幾起案子藏鹊,更是在濱河造成了極大的恐慌,老刑警劉巖转锈,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盘寡,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡黑忱,警方通過(guò)查閱死者的電腦和手機(jī)宴抚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)勒魔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人菇曲,你說(shuō)我怎么就攤上這事冠绢。” “怎么了常潮?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵弟胀,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我喊式,道長(zhǎng)孵户,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任岔留,我火速辦了婚禮夏哭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘献联。我一直安慰自己竖配,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布里逆。 她就那樣靜靜地躺著进胯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪原押。 梳的紋絲不亂的頭發(fā)上胁镐,一...
    開(kāi)封第一講書(shū)人閱讀 51,754評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音诸衔,去河邊找鬼盯漂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛署隘,可吹牛的內(nèi)容都是我干的宠能。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼磁餐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了阿弃?” 一聲冷哼從身側(cè)響起诊霹,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎渣淳,沒(méi)想到半個(gè)月后脾还,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡入愧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年鄙漏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嗤谚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡怔蚌,死狀恐怖巩步,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情桦踊,我是刑警寧澤椅野,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站籍胯,受9級(jí)特大地震影響竟闪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜杖狼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一炼蛤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蝶涩,春花似錦理朋、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至斜友,卻和暖如春炸裆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鲜屏。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工烹看, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人洛史。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓惯殊,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親也殖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子土思,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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