'java中的棧幀'

Java 虛擬機 數據結構 51碼農 2019-08-07
"
"
java中的棧幀


棧幀數據結構

棧幀(Stack Frame)是用來支持虛擬機進行方法調用和方法執行的數據結構,它是虛擬機運行時數據區中的虛擬機棧的棧元素。

棧幀(Stack Frame)存儲了方法的局部變量表、操作數棧、動態連接、和方法返回地址、額外的附加信息。

每個方法在執行的同時,都會創建一個棧幀(Stack Frame)。每一個方法從調用開始至執行完成的過程,都對應著一個棧幀在虛擬機棧裡面從入棧到出棧的過程。

棧幀的內存分配

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

當前棧幀(Current Stack Frame)

一個線程中的方法調用鏈可能會很長,很多方法都同時處於執行狀態。對於執行引擎來說,在活動線程中,只有位於棧頂的棧幀才是最有效的,稱為當前棧幀(Current Stack Frame),與這個棧幀相關聯的方法稱為當前方法。執行引擎運行的所有的字節碼指令都只針對當前棧幀進行操作。在概念模型上,典型的棧幀結構圖如下:

局部變量表

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

局部變量表的容量以變量槽(Variable Slot)為最小單位。每個變量槽都可以存儲32位長度的內存空間,例如boolean、byte、char、short、int、float、reference。

對於64位長度的數據類型(long,double),虛擬機會以高位對齊方式為其分配兩個連續的Slot空間,也就是相當於把一次long和double數據類型讀寫分割成為兩次32位讀寫。

"
java中的棧幀


棧幀數據結構

棧幀(Stack Frame)是用來支持虛擬機進行方法調用和方法執行的數據結構,它是虛擬機運行時數據區中的虛擬機棧的棧元素。

棧幀(Stack Frame)存儲了方法的局部變量表、操作數棧、動態連接、和方法返回地址、額外的附加信息。

每個方法在執行的同時,都會創建一個棧幀(Stack Frame)。每一個方法從調用開始至執行完成的過程,都對應著一個棧幀在虛擬機棧裡面從入棧到出棧的過程。

棧幀的內存分配

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

當前棧幀(Current Stack Frame)

一個線程中的方法調用鏈可能會很長,很多方法都同時處於執行狀態。對於執行引擎來說,在活動線程中,只有位於棧頂的棧幀才是最有效的,稱為當前棧幀(Current Stack Frame),與這個棧幀相關聯的方法稱為當前方法。執行引擎運行的所有的字節碼指令都只針對當前棧幀進行操作。在概念模型上,典型的棧幀結構圖如下:

局部變量表

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

局部變量表的容量以變量槽(Variable Slot)為最小單位。每個變量槽都可以存儲32位長度的內存空間,例如boolean、byte、char、short、int、float、reference。

對於64位長度的數據類型(long,double),虛擬機會以高位對齊方式為其分配兩個連續的Slot空間,也就是相當於把一次long和double數據類型讀寫分割成為兩次32位讀寫。

java中的棧幀

"
java中的棧幀


棧幀數據結構

棧幀(Stack Frame)是用來支持虛擬機進行方法調用和方法執行的數據結構,它是虛擬機運行時數據區中的虛擬機棧的棧元素。

棧幀(Stack Frame)存儲了方法的局部變量表、操作數棧、動態連接、和方法返回地址、額外的附加信息。

每個方法在執行的同時,都會創建一個棧幀(Stack Frame)。每一個方法從調用開始至執行完成的過程,都對應著一個棧幀在虛擬機棧裡面從入棧到出棧的過程。

棧幀的內存分配

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

當前棧幀(Current Stack Frame)

一個線程中的方法調用鏈可能會很長,很多方法都同時處於執行狀態。對於執行引擎來說,在活動線程中,只有位於棧頂的棧幀才是最有效的,稱為當前棧幀(Current Stack Frame),與這個棧幀相關聯的方法稱為當前方法。執行引擎運行的所有的字節碼指令都只針對當前棧幀進行操作。在概念模型上,典型的棧幀結構圖如下:

局部變量表

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

局部變量表的容量以變量槽(Variable Slot)為最小單位。每個變量槽都可以存儲32位長度的內存空間,例如boolean、byte、char、short、int、float、reference。

對於64位長度的數據類型(long,double),虛擬機會以高位對齊方式為其分配兩個連續的Slot空間,也就是相當於把一次long和double數據類型讀寫分割成為兩次32位讀寫。

java中的棧幀

java中的棧幀

其中:8bit=1b [一個Byte等於8個bit(位)],1024b=1kb

為了節省棧幀空間,局部變量表中的Slot是可以重用的,方法體中定義的變量,其作用域並不一定會覆蓋整個方法體,如果當前字節碼PC計數器的值已經超過了某個變量的作用域,那麼這個變量對應的Slot就可以交給其他變量使用。

優點 : 節省棧幀空間。

缺點 : 影響到系統的垃圾收集行為。(如大方法佔用較多的Slot,執行完該方法的作用域後沒有對Slot賦值或者清空設置null值,垃圾回收器便不能及時的回收該內存。)

操作數棧

操作數棧(operand Stack)也常稱為操作棧,它是一個後入先出棧。和局部變量表一樣,操作數棧的最大深度也在編譯的時候寫入到Code屬性的max_stacks中。

操作數棧的每一個元素可用是任意的Java數據類型,包括long和double。32位數據類型所佔的棧容量為1,64位數據類型佔用的棧容量為2。

當一個方法剛剛開始執行的時候,這個方法的操作數棧是空的,在方法執行的過程中,會有各種字節碼指令往操作數棧中寫入和提取內容,也就是出棧 / 入棧操作。例如,在做算術運算的時候是通過操作數棧來進行的,又或者在調用其它方法的時候是通過操作數棧來進行參數傳遞的。

動態連接

每個棧幀都包含一個指向運行時常量池中該棧幀所屬方法的引用,持有這個引用是為了支持方法調用過程中的動態連接(Dynamic Linking)。

Class文件的常量池中存在大量符號引用,字節碼中的方法調用指令就以常量池中指向方法的符號引用作為參數,這些符號引用一部分在類加載階段中的解析階段會轉為直接引用,這種轉化也稱為靜態解析。另外的一部分將在每一次運行時期轉化為直接引用。這部分稱為動態連接。

方法返回地址

當一個方法開始執行後,只有2種方式可以退出這個方法 :

方法返回指令 : 執行引擎遇到一個方法返回的字節碼指令,這時候有可能會有返回值傳遞給上層的方法調用者,這種退出方式稱為正常完成出口。

異常退出 : 在方法執行過程中遇到了異常,並且沒有處理這個異常,就會導致方法退出。

無論採用任何退出方式,在方法退出之後,都需要返回到方法被調用的位置,程序才能繼續執行,方法返回時可能需要在棧幀中保存一些信。用來幫助恢復它的上層方法的執行狀態。

方法退出的過程實際上就等於把當前棧幀出棧,因此退出可能執行的操作有:

1.恢復上層方法的局部變量表和操作數棧

2.把返回值(如果存在返回值)壓入調用者棧幀的操作數棧中

3.調整PC計數器的值以指向方法調用指令後面的一條指令

附加信息

虛擬機規範允許具體的虛擬機實現增強一些規範裡沒有描述的信息到棧幀之中,例如與調試相關的信息,這部分信息取決於具體的虛擬機實現。

"

相關推薦

推薦中...