您好,登錄后才能下訂單哦!
小編給大家分享一下Java虛擬機中棧幀指的是什么,希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去探討吧!
寫在前面的話:Java虛擬機是一門學問,是眾多Java大神們的杰作,由于我個人水平有限,精力有限,不能保證所有的東西都是正確的,這里內容都是經過深思熟慮的,部分引用原著的內容,講的已經很好了,不在累述。當然在這里,不可能所有細節都深層次的分析,只講到一些比較重要的概念,由于對計算機組成原理理解不深,絕大部分只能采取黑盒理論來分析。
運行時的棧幀結構(什么是棧幀?)
棧幀是虛擬機進行調用和方法執行的數據結構,簡單的說棧幀其實就是JVM運行時數據區虛擬機機棧(JVM Stack)的棧元素,,,每一個方法的執行和調用對應著一個棧幀。舉個簡單的例子,定義一個Stack ,這個Statck 中放入一些叫做棧幀的對象,這個對象中包含了局部變量表,操作數棧,動態鏈接和方法返回地址等屬性。下面,我們講一下棧幀這個對象的結構。
首先應當明白,一個線程中一個方法的調用鏈可能會很長,當中有很多方法都處在執行狀態,對于我們的執行引擎來說,只有位于棧頂的棧幀才是有效的,這個叫做當前棧幀(Concurrent Satck Frame),與這個棧幀相關的方法稱作當前方法(Concurrent Method),相應的概念模型如下:
通過棧幀的概念模型,接下來說說,棧幀這個對象的相關屬性,有什么作用?數據結構是怎樣的
1.局部變量表(Local Variable Table)
它是一組變量的存儲空間,用于存放方法上和方法內部的變量。在Java編譯期就已完成局部變量表的最大容量分配,說的直白點,局部變量表就是存儲局部變量的表,用來存儲變量用的;其中它的容量用變量槽(Variable Slot,簡稱Slot)來衡量,Slot也是最小單位;相關資料參考周志明《深入理解Java虛擬機 2版》P238;以下是相關類型的數據所占用的內存空間
從圖中可以看出,基本數據類型除了double和long分割成2個32位(也就是2個Slot)進行存儲以外,即高位對齊方式;而其他類型都只占用1個32位的Slot;另外
引用類型可能是32位也可能是64位,Java中沒有明確規定。那么虛擬機又是怎樣訪問局部變量的呢?
虛擬機通過索引定位法的方式使用局部變量表,索引值的范圍是從0到Slot的最大數量。在方法執行時,特別是執行實例方法時,那么實例變量表的第0位索引默認是方法所屬的實例對象的引用“this”對象,接著是1到Slot參數變量到方法內部的局部變量。另外為了節省棧幀空間,局部變量的Slot是可以復用的,也就是說方法參數+方法內局部變量 !=最大Slot數。由于Slot可以復用,不僅節省了空間的開銷,同時也對系統的垃圾回收起到意想不到的作用。參考P239
2.操作數棧(Operand Stack)
操作數棧是一個后入先出的棧(LIFO) ,基本原理和存儲方式和局部變量變一樣,32位的數據類型用的棧的容量大小是1,64位的就是2;方法執行的任何時候,操作數棧的深度都不會超過在max_statcks數據項中設置的最大值。參考P242,以下做個總結
1.棧楨剛創建時,里面的操作數棧是空的。
2.Java虛擬機提供指令來讓操作數棧對一些數據進行入棧操作,比如可以把局部變量表里的數據、實例的字段等數據入棧。
3.同時也有指令來支持出棧操作。
4.向其他方法傳參的參數,也存在操作數棧中。
5.其他方法返回的結果,返回時存在操作數棧中。
6.棧幀中的部分操作數棧和上一個棧幀的局部變量變存在一定的重疊,主要是為了共享數據而存在。
3.動態連接(Dynamic Linking)
每個棧幀都包含一個指向運行時常量池中該棧幀所屬性方法的引用,持有這個引用是為了支持方法調用過程中的動態連接。在Class文件的常量池中存有大量的 符號引用,字節碼中的方法調用指令就以常量池中指向方法的符號引用為參數。這些符號引用一部分會在類加載階段或第一次使用的時候轉化為直接引用,這種轉化 稱為靜態解析。另外一部分將在每一次的運行期期間轉化為直接引用,這部分稱為動態連接。
4.方法返回地址
當一個方法被執行后,有兩種方式退出這個方法。第一種方式是執行引擎遇到任意一個方法返回的字節碼指令,這時候可能會有返回值傳遞給上層的方法調用者(調 用當前方法的的方法稱為調用者),是否有返回值和返回值的類型將根據遇到何種方法返回指令來決定,這種退出方法方式稱為正常完成出口(Normal Method Invocation Completion)。
另外一種退出方式是,在方法執行過程中遇到了異常,并且這個異常沒有在方法體內得到處理,無論是Java虛擬機內部產生的異常,還是代碼中使用 athrow字節碼指令產生的異常,只要在本方法的異常表中沒有搜索到匹配的異常處理器,就會導致方法退出,這種退出方式稱為異常完成出口(Abrupt Method Invocation Completion)。一個方法使用異常完成出口的方式退出,是不會給它的調用都產生任何返回值的。
無論采用何種方式退出,在方法退出之前,都需要返回到方法被調用的位置,程序才能繼續執行,方法返回時可能需要在棧幀中保存一些信息,用來幫助恢復它的上 層方法的執行狀態。一般來說,方法正常退出時,調用者PC計數器的值就可以作為返回地址,棧幀中很可能會保存這個計數器值。而方法異常退出時,返回地址是 要通過異常處理器來確定的,棧幀中一般不會保存這部分信息。
方法退出的過程實際上等同于把當前棧幀出棧,因此退出時可能執行的操作有:恢復上層方法的局部變量表和操作數棧,把返回值(如果有的話)壓入調用都棧幀的操作數棧中,調用PC計數器的值以指向方法調用指令后面的一條指令等。
5.附加信息
虛擬機規范允許具體的虛擬機實現增加一些規范里沒有描述的信息到棧幀中,例如與高度相關的信息,這部分信息完全取決于具體的虛擬機實現。在實際開發中,一般會把動態連接,方法返回地址與其它附加信息全部歸為一類,稱為棧幀信息。
看完了這篇文章,相信你對Java虛擬機中棧幀指的是什么有了一定的了解,想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。