JVM學習筆記六:字節碼執行引擎

運行時棧幀結構

棧幀是虛擬機運行時數據區中的虛擬機棧的棧元素,棧幀存儲了方法的局部變量表,操做數棧,動態鏈接,方法返回地址,在編譯程序代碼的時候,棧幀中須要多大的局部變量表、多深的操做數棧都已經徹底肯定了,而且寫入到方法表的Code屬性之中。
jinjiprojectnaotujava

局部變量表

其最大容量由方法的Code屬性,max_locals肯定,局部變量表的容量以變量槽(Slot)爲最小單位,Long和Double佔用兩個空間,其讀寫是非原子性的,其會佔用n與n+1兩個Slot,不容許採用任何方式單獨訪問其中的一個Slot。性能

在方法執行時,虛擬機是使用局部變量表來完成參數值到變量表的傳遞,若是執行的是實例方法,那麼局部變量表第0位索引的Slot默認是用於傳遞方法所屬的對象實例的引用,其他參數從索引1開始佔用Slot,參數表分配完畢後,再根據方法體內部定義的變量順序和做用域分配其他的Slot,爲了儘量的節省棧幀空間,局部變量表中的Solt是能夠重用的,當PC計數器的值,已經超出方法體中定義的變量的做用域時,其佔用的Slot會被其餘做用域的變量重用。對象

操做數棧

其最大深度由方法的Code屬性的max_stacks決定,有些虛擬機實現上,會讓相鄰的兩個棧幀出現一些 共享部分,方便方法調用之間共享數據。blog

動態鏈接

每一個棧幀都包含一個指向運行時常量池中該幀所屬方法的引用,這個引用是爲了支持方法調用過程當中的動態鏈接。繼承

方法返回地址

當一個方法執行之後,只有兩種方式能夠退出這個方法,一個是執行引擎遇到一個返回的字節碼指令,這時候可能會有返回值傳遞給上層的方法調用者,這種退出方法被稱爲正常完成出口,另外一種退出方式是,在方法的執行過程當中遇到了異常,只要在本方法的異常表中沒有搜索到匹配的異常處理器,就會致使方法退出,這種退出方式被稱爲異常完成出口,這種方式是不會給它的上層調用者返回任何返回值的。索引

不管任何方式退出,都須要返回到方法被調用的位置,程序才能繼續執行,因此方法退出時會恢復上層方法的局部變量表和操做數棧,把返回值壓入調用者的操做數棧,調整PC至下一條指令地址。ip

方法調用

方法調用階段惟一的任務就是肯定被調用方法的版本作用域

方法調用的方式

方法的調用包括解析與分派兩種方式虛擬機

  1. 解析能夠在類加載的解析階段,將符號引用直接轉化爲直接引用,這種解析成立的前提是,方法的運行以前就能夠肯定調用的版本是惟一的,並且是在運行期不可變的。
  2. 分派又分爲靜態分派與動態分派,重載機制就是由靜態分派實現,而重寫則是由動態分派實現。

動態分派的解析過程(invokevirtual指令爲例):編譯

  1. 找到操做數棧頂的第一個元素所指向的對象的實際類型,記作C。
  2. 若是在類型C中找到與常量中的描述符和簡單名稱都相符的方法,則進行訪問權限校驗,若是經過則返回這個方法的直接引用,查找過程結束,不然,返回java.lang.IllegalAccessError
  3. 不然,按照繼承關係從下往上對C的各個父類進行第2步的搜索和驗證過程。
  4. 若是沒有找到合適的方法,拋出java.lang.AbstractMethodError異常。

出於性能的考慮,會爲類在方法區創建一個虛方法表,使用虛方法表索引來代替元數據查找以提升性能
jinjiprojectnaotu

參考資料

本文參考:《深刻理解Java虛擬機》

相關文章
相關標籤/搜索