×

深入理解Java之java虛擬機干凈利落的規(guī)范總結(jié) 上

  • 作者:新網(wǎng)
  • 來源:新網(wǎng)
  • 瀏覽:100
  • 2018-05-03 17:57:51

要去正確地實現(xiàn)一臺Java虛擬機,就需要正確地讀取class文件中每一條字節(jié)碼指令并且能正確執(zhí)行這些指令所蘊含的操作即可。

   hosting.jpg

<div>  要去正確地實現(xiàn)一臺Java虛擬機,就需要正確地讀取class文件中每一條字節(jié)碼指令并且能正確執(zhí)行這些指令所蘊含的操作即可。
  數(shù)據(jù)類型
  和Java語言類似,在Java虛擬機中的數(shù)據(jù)類型也可以分為基本類型和引用類型兩種,所以也存在原始值和引用值兩種類型的數(shù)值。它們可用于變量賦值、參數(shù)傳遞、方法返回和運算操作。
  原始類型與值
  Java虛擬機所支持的原始數(shù)據(jù)類型包括數(shù)值類型、boolean類型、和returnAddress類型
  數(shù)值類型分為整數(shù)類型和浮點類型,分別是char,byte,short,int,long;浮點類型即float和double,這里和Java語言中的一致。
  returnAddress翻譯過來是返回地址,其實returnAddress類型的值指向一條虛擬機指令的操作碼。它在虛擬機中比較典型的一個應(yīng)用場景是用于jsr程序段落跳轉(zhuǎn),在try-catch異常處理以及finally代碼塊經(jīng)常出現(xiàn)。和數(shù)值類的原生類型不同,returnAddress類型在Java語言之中并不存在相應(yīng)的類型,而且也無法在程序運行期間修改。
  雖然Java虛擬機定義了boolean這種數(shù)據(jù)類型,但是只對它提供了十分有限的支持。在Java虛擬機中并沒有任何供boolean值專用的字節(jié)碼指令,Java語言表達式所操作的boolean值,在編譯之后都使用Java虛擬機中的int數(shù)據(jù)類型來代替。(Java虛擬機會把boolean數(shù)組元素中的true采用1來表示,false采用0來表示,當Java編譯器把Java語言中的boolean類型值映射為Java虛擬機的int類型值時,也必須用上述表示方式)
  引用類型與值
  Java虛擬機中有三種引用類型:類類型、數(shù)組類型和接口類型。它們分別指向動態(tài)創(chuàng)建的類實例、數(shù)組實例和某個接口的類實例或數(shù)組實例。
  數(shù)組類型最外面那一維元素的類型叫做數(shù)組類型的組件類型。一個數(shù)組的組件類型也可以是數(shù)組。從任意一個數(shù)組開始,如果發(fā)現(xiàn)其組件類型也是數(shù)組類型,那就繼續(xù)取這個小數(shù)組的組件類型,不斷執(zhí)行這樣的操作,最終一定可以遇到組件類型不是數(shù)組的情況,這時就把這種類型成為本數(shù)組的元素類型。數(shù)組的元素類型必須是原生類型、類類型或者接口類型之一。
  在引用類型的值中還有一個特殊的值:null,當一個引用不指向任何對象的時候,它的值就用null來表示。一個為null的引用,起初并不具備任何實際的運行期類型,但是它可轉(zhuǎn)型為任意的引用類型。引用類型的默認值就是null。Java虛擬機規(guī)范并沒有規(guī)定null在虛擬機實現(xiàn)中應(yīng)當怎樣用編碼來表示。
  運行時數(shù)據(jù)區(qū)域
  棧幀:棧幀是用來存儲數(shù)據(jù)和部分過程結(jié)果的數(shù)據(jù)結(jié)構(gòu),同時也用來處理動態(tài)鏈接、方法返回值和異常分派。棧幀又是存儲在棧中(包括Java虛擬機棧和本地方法棧),它隨著方法調(diào)用而創(chuàng)建,隨著方法結(jié)束而銷毀,其實也就是一個方法執(zhí)行的過程也對應(yīng)著棧幀的入棧和出棧的過程。無論方法是正常完成還是異常完成(拋出了在方法內(nèi)未被捕獲的異常)都算作方法結(jié)束。棧幀的存儲空間由創(chuàng)建它的線程分配在Java虛擬機棧之中,每一個棧幀都有自己的本地變量表、操作數(shù)棧和指向當前方法所屬的類的運行時常量池的引用。
  本地變量表和操作數(shù)棧的容量在編譯期確定,并通過相關(guān)方法的code屬性保存及提供給棧幀使用。因此,棧幀數(shù)據(jù)結(jié)構(gòu)的大小僅僅取決于Java虛擬機的實現(xiàn)。實現(xiàn)者可以在調(diào)用方法的時候給它們分配內(nèi)存。
  在某條線程執(zhí)行的過程中的某個時間點,只有目前正在執(zhí)行的那個方法的棧幀是活動的。這個棧幀稱為當前棧幀,這個棧幀對應(yīng)的方法稱為當前方法,定義這個方法的類稱作當前類。對局部變量表和操作數(shù)棧的各種操作,通常都是值對當前棧幀的局部變量表和操作數(shù)棧所進行的操作。
  如果當前方法調(diào)用了其他方法,或者當前方法執(zhí)行結(jié)束,那這個方法的棧幀就不再是當前棧幀了。調(diào)用新方法時,新的棧幀也會隨之而創(chuàng)建,并且會隨著程序控制權(quán)移交到新方法而成為新的當前棧幀。方法返回之際,當前棧幀會傳回此方法給前一個棧幀,然后虛擬機會丟棄當前棧幀,使得前一個棧幀重新成為當前棧幀。
  需要特別注意的是,棧幀是線程本地私有的數(shù)據(jù),不可能在一個棧幀之中引用另外一個線程的棧幀。
  局部變量表
  每個棧幀內(nèi)部都包含一組稱為局部變量表的變量列表。棧幀中局部變量表的長度由編譯器決定,并卻存儲于類或接口的二進制表示之中,即通過方法的code屬性保存及提供給棧幀使用。
  一個局部變量可以保存一個類型為boolean、byte、char、short、int、float、reference或returnAddress的數(shù)據(jù)。兩個局部變量可以保存一個類型為long或double的數(shù)據(jù)。
  局部變量使用索引來進行定位訪問。首個局部變量的索引值為0。局部變量的索引值是個整數(shù),它大于等于0,且小于局部變量表的長度。Java虛擬機使用局部變量表來完成方法調(diào)用時的參數(shù)傳遞。當調(diào)用類方法時,它的參數(shù)將會依次傳遞到局部變量表中從0開始的連續(xù)位置上。當調(diào)用實例方法時,第0個局部變量一定用來存儲該實例方法所在對象的引用(即Java語言中的this關(guān)鍵字)。后續(xù)其他參數(shù)將會傳遞至局部變量表中從1開始的連續(xù)位置上。
  操作數(shù)棧:每個棧幀內(nèi)部都包含一個稱為操作數(shù)棧的后進后出棧。棧幀中操作數(shù)棧的最大深度由編譯期決定,并且通過方法的code屬性保存及提供給棧幀使用。棧幀剛創(chuàng)建的時候操作數(shù)棧是空的。Java虛擬機提供一些字節(jié)碼指令來從局部變量表或者對象實例的字段中復(fù)制常量或變量值到操作數(shù)棧中,也提供了一些指令用于從操作數(shù)棧取走數(shù)據(jù)、操作數(shù)據(jù)以及把操作結(jié)果重新入棧。在調(diào)用方法時,操作數(shù)棧也用來準備調(diào)用方法的參數(shù)以及接收方法返回結(jié)果。例如iadd字節(jié)碼指令的作用是將兩個int類型的數(shù)值相加,它要求在執(zhí)行之前操作數(shù)棧的棧頂已經(jīng)存在兩個由前面的其他指令所放入的int類型數(shù)值。在執(zhí)行iadd指令時,兩個int類型數(shù)值出棧,相加求和之后求和結(jié)果重新入棧。操作數(shù)棧的每個位置上可以保存一個Java虛擬機中定義的數(shù)據(jù)類型的值,包括long和double類型。在任意時刻,操作數(shù)棧都會有一個確定的棧深度,一個long或者double類型的數(shù)據(jù)會占用兩個單位的棧深度,其他數(shù)據(jù)類型則會占用一個單位的棧深度。
  動態(tài)鏈接
  每個棧幀內(nèi)部都包含一個指向當前方法所在類型的運行時常量池的引用,以便對當前方法的代碼實現(xiàn)動態(tài)鏈接。在class文件里面一個方法若要調(diào)用其他方法,或者訪問成員變量,則需要通過符號引用來表示。動態(tài)鏈接的作用就是將這些符號引用所表示的方法轉(zhuǎn)換為對實際方法的直接引用。類加載的過程中將要解析尚未被解析的符號引用,并且將對變量的訪問轉(zhuǎn)化為變量在程序運行時,位于存儲結(jié)構(gòu)中的正確偏移量。由于對其他類中的方法和變量進行了晚期綁定,所以即便那些類發(fā)生變化,也不會影響調(diào)用它們的方法。
  對象的表示
  Java虛擬機規(guī)范不強制規(guī)定對象的內(nèi)部結(jié)構(gòu)應(yīng)該如何表示。在具體實現(xiàn)中,一般有兩種對象的訪問方式,分別是通過句柄訪問對象以及通過直接指針訪問對象。
  在之前的博客里我也總結(jié)過這兩種對象訪問方式的優(yōu)劣,想要了解的同學可以參考這篇博客
  特殊方法
  在Java虛擬機層面,Java編程語言的構(gòu)造器是以一個名為的特殊實例初始方法的形式出現(xiàn)的。這個方法名稱是由編譯器命名的,因為它并非一個合法的Java方法名字,不可能通過程序編碼的方式實現(xiàn)。實例初始化方法的初始化期間,通過Java虛擬機的invokespecial指令來調(diào)用,而且只能在尚未初始化的實力上調(diào)用該指令。構(gòu)造器的訪問權(quán)限也會約束由該構(gòu)造器所衍生出來的實例初始化方法。
  一個類或者接口最多可以包含不超過一個類或接口的初始化方法,類或接口就是通過這個方法完成初始化的。這個方法是一個不包含參數(shù)的、返回類型為void的方法,名為。
  在class文件中把其他方法命名為是沒有意義的,這些方法并不是類或接口的初始化方法,它們既不能被字節(jié)碼指令調(diào)用,也不會被虛擬機自己調(diào)用。當class文件的版本號不小于51.0時,方法想要成為類或接口的初始化方法,必須設(shè)置ACC_STATIC標志。
  異常
  Java虛擬機里面的異常使用Throwable或其子類的實例來表示,拋異常的本質(zhì)實際上是程序控制權(quán)轉(zhuǎn)移的一種即時的、非局部的轉(zhuǎn)換---從異常拋出的地方轉(zhuǎn)換至異常處理的地方。
  絕大多數(shù)異常的產(chǎn)生都是由于當前線程執(zhí)行的某個操作所導(dǎo)致的,這種可以稱為同步異常。與之相對,異步異常可以在程序執(zhí)行過程中隨時發(fā)生。Java虛擬機中異常的出現(xiàn)總是由下面三種原因之一導(dǎo)致的:
  athrow字節(jié)碼指令被執(zhí)行;
  虛擬機同步檢測到程序發(fā)生了非正常的執(zhí)行情況,這時異常必將緊接著發(fā)生在非正常執(zhí)行情況的字節(jié)碼指令之后拋出,而不會在執(zhí)行程序的過程中隨時拋出。例如:程序所執(zhí)行的操作可能會引發(fā)異常---當字節(jié)碼指令所蘊含的操作違反了Java語言的語義,如訪問一個超出數(shù)組邊界范圍的元素,或者是當程序在加載或者連接時出現(xiàn)錯誤;還有一種異常是使用某些資源的時候產(chǎn)生資源限制,比如說使用了太多的內(nèi)存。
  由于以下原因,導(dǎo)致了異步異常的發(fā)生: 調(diào)用了Thread或者ThreadGroup的stop方法;Java虛擬機實現(xiàn)發(fā)生了內(nèi)部錯誤。
  當某個線程調(diào)用了stop方法時,將會影響到其他線程,或者在特定線程組中的所有線程。因為stop方法的執(zhí)行常常會導(dǎo)致出現(xiàn)數(shù)據(jù)不一致的情況,這時候其他線程中出現(xiàn)的異常就是異步異常,因為這些異??赡艹霈F(xiàn)在線程執(zhí)行過程中的任何位置。虛擬機的內(nèi)部錯誤也被認為是一種異步異常。
  虛擬機錯誤
  InternalError:實現(xiàn)虛擬機的軟件錯誤、底層主機系統(tǒng)的軟件錯誤及硬件錯誤都會導(dǎo)致Java虛擬機出現(xiàn)內(nèi)部錯誤,InternalError是一個異步異常,它可能出現(xiàn)在程序中的任何位置;
  OutOfMemoryError:當Java虛擬機實現(xiàn)耗盡了所有虛擬或物理內(nèi)存,并且內(nèi)存自動管理子系統(tǒng)無法回收到創(chuàng)建新對象所需的足夠內(nèi)存空間時,虛擬機將拋出OutOfMemoryError。
  StackOverflowError:當Java虛擬機實現(xiàn)耗盡了線程全部的棧空間時,虛擬機將會拋出StackOverflowError。
  UnKnownError:當某種錯誤或異常出現(xiàn),但虛擬機實現(xiàn)又無法確定它具體是哪種異?;蝈e誤,將會拋出UnKnownError。
  由于通常虛擬機會對代碼進行優(yōu)化,例如指令重排。那么在異常發(fā)生的時候,有一些在異常出現(xiàn)位置之后的代碼可能已經(jīng)執(zhí)行了,那這些優(yōu)化過的代碼必須保證它們提前執(zhí)行所產(chǎn)生的影響對用戶程序來說是不可見的。
 

免責聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻自行上傳,本網(wǎng)站不擁有所有權(quán),也不承認相關(guān)法律責任。如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,請發(fā)送郵件至:operations@xinnet.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,本站將立刻刪除涉嫌侵權(quán)內(nèi)容。

免費咨詢獲取折扣

Loading