1. 程式人生 > >JVM字節碼執行引擎和動態綁定原理

JVM字節碼執行引擎和動態綁定原理

找不到 順序 入棧 兩種 運行時 mage 過程 狀態 對象

1.執行引擎

  • 所有Java虛擬機的執行引擎都是一致的: 輸入的是字節碼文件,處理過程就是解析過程,最後輸出執行結果。
  • 在整個過程不同的數據在不同的結構中進行處理。

2.棧幀

  • jvm進行方法調用和方法執行的數據結構,是虛擬機棧的元素。
  • 技術分享圖片(圖片來自網絡)
  1. 棧幀包括:局部變量表、操作數棧、動態鏈接、方法返回地址等
  2. 編譯期就確定了需要多大的局部變量表,多深的操作數棧,這些信息全在字節碼中。
  3. 只有位於棧頂的棧幀才有效,稱為當前棧幀,所對應的方法就是當前正在執行的方法。

2.1 局部變量表

  • 存放方法參數和方法內部定義的局部變量。
  1. 容量以變量槽slot為單位,slot內存大小隨著需求而變化並且不固定。
  2. 方法執行時jvm使用局部變量表完成參數值到參數列表的傳遞過程。
  3. slot可以被其他變量復用。
  4. 局部變量不存在準備階段,所以不會賦予系統初始值,如果不初始化那麽他就不能使用。
  5. jvm通過索引定位的方式定位slot,從0到最大slot數量。0位索引slot是用來存放方法所屬對象實例的引用(this),之後按參數列表分配slot,再後按照局部變量順序分配slot。

2.2操作數棧

  • 方法剛剛開始執行時為空,在執行過程中會有各種字節碼指令往操作數棧中寫入和提取內容,也就是入棧/出棧操作。
  • 概念上兩個棧幀相互獨立,但大多數虛擬機會存在一些優化,讓下面棧幀的操作數棧部分區域和上面棧幀的部分局部變量表重合,成為共享區域。

2.3動態鏈接

  • 保存 指向運行時常量池中 該棧幀所屬方法的 引用。
  • 作用就是 運行期間將符號引用轉化為直接引用。

2.4方法返回地址

  • 保留一些退出方法時 上層方法執行狀態 的信息

3.方法的調用,動態綁定過程。

  • 編譯過程不包括傳統的連接,class文件中只是存符號引用,而不是直接引用。
  • 方法調用就是確定該方法是哪個類的哪個方法換個說法就是綁定,這不同於方法執行。
  1. 解析

    • 符號引用轉化為直接引用,因為編譯器並不知道分配內存後某個變量具體內存位置,所以編譯時使用一個符號代替,分配內存後該變量所在的內存位置就等於這個符號,解析階段找到這個符號對應的內存位置然後指向她,這就是符號引用轉化為直接引用。
    1. 類加載的解析階段會把 部分符號引用轉化為直接引用,但這種解析的前提條件就是:方法在程序執行之前就有一個就可以確定的版本,並且在運行期間不可變。
    2. 編譯期可知運行期不可變這種方法有static和private方法,想想也是,這兩種方法只有定義他們的類才能調用,他們一出生就確定了唯一的主人。他們不可能被繼承或者重寫其他版本。
    3. 實例構造器,父類方法這2中也能確定唯一的版本,所以這些方法也是在類加載階段解析為直接引用。
    4. 靜態方法,私有方法,實例構造器,父類方法這些方法可確定唯一版本所以統稱為 非虛方法,final方法也是非虛方法。
  2. 分派調用

    • 分派調用就是多態特征的體現,在重載重寫的方法中正確確定版本。
    1. 靜態類型和動態類型
      • Human man = new Man();
      • Human 就是變量man 的靜態類型, Man 就是man 的實際類型。
      • 靜態類型在編譯期可知,動態類型在運行期才能確定
    2. 靜態分派:根據參數的靜態類型確定該方法使用的版本
      • 方法被重載了好幾個版本,確定要使用哪一個版本就是通過當前調用方法傳入參數的靜態類型確定版本。
      • 靜態分派會找到一個和參數靜態類型最適合的版本,如 int 類型傳入多個沒有int的重載版本中還會找到float版本。
      • 靜態分派在編譯期確定調用哪一個版本,並把符號引用記錄下來。
      • 註意靜態分派只確定了方法的版本,如果一個類沒有繼承其他類當前方法也不是覆寫了父類方法,那麽他就只有這一個版本可用,如果重寫了父類方法,那麽就由動態分派來確定使用哪個重寫方法。
    3. 動態分派:運行期間根據調用方法的對象的實際類型確定使用哪個類的方法,也就是確定使用哪個重寫方法。編譯期間無法確定實際類型
      1. 找到調用當前方法的對象的實際類型
      2. 在實際類型中由靜態分派確定方法版本。
      3. 如果找到對應版本則檢查訪問權限如果通過則返回此方法的引用。
      4. 如果找不到則從下往上在父類中找,如果找不到則拋出異常。
    4. 單分派多分派
      • 方法的接收者和參數統稱為綜量
      • 靜態分派是根據方法參數確定的,方法參數可以有多個所以是多個宗量,屬於多分派。
      • 動態分派是根據一個實際類型確定的所以屬於單宗量,所以是單分派。
      • Java 目前是一門靜態多分派,動態單分派的語言。
    5. 靜態分派和動態分派的區別
      1. 靜態分派通過參數類型查找重載版本,並且是參數的靜態類型。
      2. 動態分派通過調用方法的對象查找重寫版本,並且是對象的實際類型。

JVM字節碼執行引擎和動態綁定原理