第8章 虛擬機字節碼執行引擎
8.2 運行時棧幀結構
棧幀(Stack Frame)是用于支持虛擬機進行方法調用和方法執行的數據結構。
每一個棧幀包括了局部變量表、操作數棧、動態連接、方法返回地址和一些額外的附加信息。
在活動線程中,只有位于棧頂的棧幀才是有效的,稱為當前棧幀 Current Stack Frame,與這個棧幀相關聯的方法稱為當前方法。
局部變量表:
Local Variable Table是一組變量值存儲空間,用于存放方法參數和方法內部定義的局部變量。
在Java程序編譯為Class文件時,就在方法的Code屬性中確定了該方法所需要分配的局部變量表的最大容量。
局部變量表的容量以變量槽(slot)為最小單位。
在方法執行時,虛擬機是使用局部變量表完成參數值到參數變量列表的傳遞過程。
如果執行的是實例方法(非static的方法),那局部變量表中第0位索引的Slot默認用于傳遞方法所屬對象實例的引用,在方法中可以通過關鍵字“this”來訪問這個隱含的參數,其余參數則按照參數順序排列,占用從1開始的局部變量slot.
操作數棧:
Operand Stack也常稱為操作棧,它是一個后入先出(Last In First Out, LIFO)棧。
當一個方法剛剛開始 執行的時候,這個方法的操作數棧是空的,在方法的執行過程中,會有各種字節碼指令往操作數棧中寫入和提取內容,也就是入棧、出棧操作。
例:整數加法的字節碼指令iadd在運行時操作數棧中最接近棧頂的兩個元素已經存入了兩個int型的數據,當執行這個指令時,會將這兩個int值出棧并相加,然后將相加的結果入棧。
動態連接:
每個棧幀都包含一個指向運行時常量池中該棧幀所屬方法的引用,持有這個引用是為了支持方法調用過程中的動態連接.
方法返回地址:
當一個方法開始執行后,只有兩上方式可以退加該方法:
1 執行引擎遇到任意一個方法返回的字節碼指令,正常退出
2 在方法執行過程中出現異常,并且這個那異常沒有在方法體內得到處理。
附加信息:
8.3方法調用
方法調用階段唯一的任務就是確定被調用方法的版本(即調用哪一個方法)
解析:
所有方法調用中的目標方法在Class里面都是一個常量池中的符號引用,會將其中的一部分符號引用轉化為直接引用。主要包括靜態方法和私有方法兩大類。
分派:
分派調用過程將為揭示多態特征的一些最基本的體現。
1、靜態分派
Human man = new Man();
虛擬機在重載時是通過參數的靜態類型(Human)而不是實際類型( Man )作為判定依劇的。
虛擬機會根據類型進行自動類型轉換或裝箱,可變長參數的重載優先級是最低的。
2、動態分派
與多態性的另一個重要體現 重寫 override 有著很密切的關聯。在判斷是調用父類中的方法還是子類中的覆蓋的方法時,根據對父類實例化的子類的不同,調用不同子類中覆寫的方法。
3、單分派與多分派
方法的接收者與方法的參數統稱為方法的宗量。單分派是根據一個宗量對目標方法進行選擇,多分派則是根據多于一個宗量對目標方法進行選擇。
Java1.6是一門靜態多分派、動態單分派的語言。
4、虛擬機動態分派的實現
由于動態分派是非常頻繁的動作,因此為類的方法區中建立一個虛方法表。
虛方法表中存放著各個方法的實際入口地址,如果子類沒有重寫父類的方法,那么入口是一致的。
如果子類重寫了,那么子類方法中的地址將會替換為子類的實現版本的入口地址。
新聞熱點
疑難解答