7.虛擬機字節碼執行引擎

運行時棧幀結構

棧幀是用於支持虛擬機進行方法調用和方法執行的數據結構。棧幀存儲了方法的局部變量表,操作數棧,動態連接和方法返回地址等信息

前面說到class文件的方法表集合,每一個方法表後面都可以有一個code屬性,存放方法體裏面的代碼翻譯過來的字節碼指令,code屬性的參數有最大操作數棧深度,局部變量表的大小,這些都是在編譯期間確定的。那麼在執行引擎運行字節碼文件時,調用一個方法就會在虛擬機棧生成一個方法對應的棧幀,棧幀是線程私有。對於執行引擎,位於棧頂的棧幀是有效的。那麼棧幀的結構是由是什麼樣的?

局部變量表

局部變量表以一組變量存儲空間,存放方法的參數和內部定義的局部變量。變量槽slot是局部變量的最小存儲單位。關於slot存儲在class文件結構code屬性中說明。

JVM通過slot的數量從0開始作爲索引使用局部變量表,使用的過程就是完成參數值到參數變量列表的傳遞過程。參數值在方法表的LocalVariableTable屬性裏,如下可以看見class文件的LocalVariableTable屬性。局部變量表的第0個索引就是方法所屬的this對象,其餘參數按照參數表順序排列。
在這裏插入圖片描述在這裏插入圖片描述
前面說過局部變量表的slot可以根據變量的作用域複用,那麼對於垃圾回收會有什麼樣的影響

image
place的作用範圍只在括號內,那運行到System.gc()按道理place可以被回收但是並沒有

當加入代碼int a=0;根據slot複用規則,a會存放place之前的變量槽,這個時候在進行gc,發現place被回收
在這裏插入圖片描述
對於局部變量表中的變量,不同於類變量,我們知道類變量有兩次賦值操作。一次在準備階段賦值成變量類型的零值,所以類變量申明完就可以使用。第二次在初始化階段,賦值爲程序中的值。對於局部變量之聲明沒有賦值是不能使用的。

操作數棧

方法的操作數棧的最大深度在編譯完之後就確定了,存儲在方法的code屬性中,操作數棧是一個後入先出的棧,當一個方法剛剛被調用的時候,這個棧是空的,執行過程中,會有各種字節碼指令往操作數棧中寫入和提取內容。

比如在執行iadd字節碼指令時,會有兩個int類型的數據在操作數棧頂,遇到這個iadd,會將兩個int數值出棧,並將結果入棧。

一個方法與另一個方法的操作數棧之間會有部分重疊。

動態連接

每一個棧幀中都包含一個指向運行時常量中該棧幀所屬方法的引用,這樣就可以支持動態連接。

class文件的常量池有大量的符號引用,當執行字節碼指令的方法調用指令時,就以常量池中指向方法的符號引用作爲參數。這些引用一部分會在類加載階段或者第一次使用轉化爲直接引用。還有一部分將在每一次運行期間轉化爲直接引用,這部分就叫做動態連接

方法返回地址

當一個方法開始執行,有兩種方式退出這個方法

第一種是執行引擎遇到返回字節碼指令,說明方法正常退出,可能會把返回值傳遞給上層調用者或者跳轉到下一條指令

另一種是在執行過程中遇到異常,並且這個異常沒有在程序中得到處理不論是jvm產生的異常還是athrow字節碼指令產生的異常,只要是在異常表中沒有收到匹配的異常,方法就會非正常退出,這個時候方法是不會給上次調用返回值的

不管何種方式退出方法,都對應這方法棧幀的出棧過程,所以方法退出執行的操作:

回覆上層方法的局部變量表和操作數棧,把返回值(有)壓入調用者棧幀的操作數棧,調整PC計數器的值執行方法調用執行完的下一條要執行的指令

附加信息

增加一些額外信息到棧幀中

一般把方法返回地址,動態連接和附加信息稱爲棧幀信息

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