十五:運行時棧幀結構

棧幀( Stack frame)

用於支持虛擬機進行方法調用和方法執行的數據結構,它是虛擬機運行時數據區中的虛擬機棧(Virtual Machine Stack)s的棧元素。棧幀存儲了方法的局部變量表、操作數棧、動態連接和方法返回地址等信息。每一個方法從調用開始至執行完成的過程,都對應着一個棧幀在虛擬機棧裏面從入棧到出棧的過程。

在編譯程序代碼的時候,棧幀中需要多大的局部變量表,多深的操作數棧都已經完全確定了,並且寫入到方法表的Code屬性之中,因此一個棧幀需要分配多少內存,不會受到程序運行期變量數據的影響,而僅僅取決於具體的虛擬機實現。

只有位於棧頂的棧幀纔是有效的,稱爲當前棧幀(Current Stack Frame),與這個棧幀相關聯的方法稱爲當前方法(Current Method)。

 

局部變量表

定義:

局部變量表(Local Variable Table)是一組變量值存儲空間,用於存放方法參數和方法內部定義的局部變量。在Java程序編譯爲Class文件時,就在方法的Code屬性的max locals數據項中確定了該方法所需要分配的局部變量表的最大容量。

局部變量表的容量以變量槽(Variable Slot,下稱Slot)爲最小單位,一個Slot可以容納存放一個32位以內的數據類型。Java中佔用32位以內的數據類型有boolean、bye、char、short、int、foat、reference和return Address8種類型

對於64位數據類型,虛擬機會以高位對齊的方式爲其分配兩個連續的Slot空間

(reference類型則可能是32位也可能是64位)64位的數據類型只有long和double兩種。值得一提的是,這裏把long和double數據類型分割存儲的做法與“long和double的非原子性協定”中把一次long和double數據類型讀寫分割爲兩次32位讀寫的做法有些類似,但是由於局部變量表建立在線程的堆棧上,是線程私有的數據,無論讀寫兩個連續的Sot是否爲原子操作,都不會引起數據安全問題。虛擬機在讀取64位數據的兩個Slot時,不會單獨讀取其中一個,否則會拋出異常。

附:

reference應該實現的功能:一是從此引用中直接或間接地查找到對象在Java堆中的數據存放的起始地址索引,二是此引用中直接或間接地查找到對象所屬數據類型在方法區中的存儲的類型信息,否則無法實現Java語言規範中定義的語法約束約束。

return Address類型目前非常少見了,是以前用來實現異常處理的,現在已經由異常表來代替了。

 

局部變量和類變量不一樣的是:如果一個局部變量定義了但沒有賦初始值是不能使用的,不要認爲Java中任何情況下都存在諸如整型變量默認爲0,布爾型變量默認爲false等這樣的默認值。

 

操作數棧

在概念模型中,兩個棧幀作爲虛擬機棧的元素,是完全相互獨立的。但在大多虛擬機的實現裏都會做一些優化處理,令兩個棧幀出現一部分重疊

 

動態連接

 

方法返回地址

方法正常退出時,調用者的PC計數器的值可以作爲返回地址,棧幀中很可能會保存這個計數器值

而方法異常退出時,返回地址是要通過異常處理器表來確定的,棧幀中一般不會保存這部分信息

方法退出的過程實際上就等同於把當前棧幀出棧,因此退出時可能執行的操作有:恢復上層方法的局部變量表和操作數棧,把返回值(如果有的話)壓入調用者棧幀的操作數棧中,調整PC計數器的值以指向方法調用指令後面的一條指令等

這也是爲什麼遞歸耗時的原因所在

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章