1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        淺談 JVM 5:方法調(diào)用機制

        共 2889字,需瀏覽 6分鐘

         ·

        2022-02-23 05:54

        經(jīng)歷了前文中類加載機制、JVM 邏輯區(qū)域劃分和運行時棧幀及方法字節(jié)碼執(zhí)行過程等內(nèi)容的沉淀之后,我們這次聊聊 JVM 中方法調(diào)用是如何發(fā)生的,以及靜態(tài)綁定和動態(tài)綁定是什么。

        先從一段 Java 代碼及其對應(yīng)字節(jié)碼看起。

        // javaprivate static int methodA() {    return 100;}
        private void methodB() { methodA();}// methodB's bytecode0 invokestatic #7 3 pop4 return

        Java 代碼部分比較簡單,在方法?methodB?中調(diào)用了?methodA。在?methodB?字節(jié)碼中,invokestatic #7?部分對應(yīng)了方法調(diào)用功能。我們可以發(fā)現(xiàn),代表了目標方法的?#7?符號包含類名?InvokeDemo、方法名?methodA?以及方法描述符?()I,即方法參數(shù)類型和返回值類型。

        由此我們知道,invokestatic?方法調(diào)用指令需要類名、方法名、方法描述符(方法參數(shù)類型 + 返回值類型)這些信息來識別一個方法。其實除了此指令外,其他方法調(diào)用指令也都需要這些信息,無論是重載的方法還是重寫的方法。對于重載的方法,JVM 在編譯期就可以完成方法符號的解析和識別,所以對于 JVM 來說不存在重載的概念。而對于重寫方法的符號解析需要在運行期確定。

        類似于重載方法這種在編譯期就可以解析的方法,可以稱之為靜態(tài)綁定;對于重寫這種在運行時才能解析的方法,可以稱之為動態(tài)綁定。

        方法調(diào)用指令

        除了?invokestatic?之外,方法調(diào)用還有其他幾種指令。同樣,我們先來看一段示例代碼。

        public class InvokeDemo {    private static int methodA() {        return 100;    }
        private void methodB() { methodA(); // invokestatic }
        private void methodC() { methodB(); // invokevirtual }
        interface IMethod { void methodD(); }
        class MethodImpl implements IMethod { @Override public void methodD() { } }
        private void methodE() { IMethod iMethod = new MethodImpl(); // invokespecial iMethod.methodD(); // invokeinterface }
        private void methodF() { new Thread( () -> {} // invokedynamic ); }}

        從上述代碼可以看出,方法調(diào)用指令包括:

        ?invokestatic:靜態(tài)方法的調(diào)用;?invokespecial:構(gòu)造器、私有實例等方法的調(diào)用;?invokevirtual:非私有實例方法的調(diào)用;?invokeinterface:接口方法的調(diào)用。?invokedynamic:lambda 表達式等調(diào)用。

        按照綁定類型分類如下:

        ?靜態(tài)綁定:invokestatic、invokespecial?態(tài)綁定invokevirtual、invokeinterface


        其中?invokedynamic?指令較為特殊,在此先不談及。

        對于?invokevirtual?和?invokeinterface,大部分情況為動態(tài)綁定。但如果方法能夠唯一確定,比如被?final?修飾,就可以使用靜態(tài)綁定直接解析。

        方法調(diào)用機制

        方法符號解析

        根據(jù)上文我們知道,對一個方法的定位需要類名、方法名、方法描述符(方法參數(shù)類型 + 返回值類型)信息。以一個類方法的方法定位為例,其過程如下:

        1.在調(diào)用類中,根據(jù)方法名和描述符查找方法;2.未找到時,遞歸查找它的父類;3.仍未找到時,在其接口中查找。

        經(jīng)過以上過程,方法的符號引用被解析為實際引用。對于靜態(tài)綁定,實際引用為指向方法的的指針;對于動態(tài)綁定,實際引用為方法表的索引。

        方法定位與方法表

        我們以?invokevirtual?和?invokeinterface?兩個指令為例,談?wù)剟討B(tài)綁定方法的調(diào)用。

        JVM 采用使用空間換取時間的方式來實現(xiàn)動態(tài)綁定,為每個類生成對應(yīng)方法表來定位目標方法。方法表根據(jù)指令分為?invokevirtual?的虛方法表 vtable 和?invokeinterface?的接口方法表 itable。其中的每個元素指向當前類或祖先類的方法。

        方法表的特征要求如下:

        1.跟 Java 的繼承特征一致,子類方法表包含父類方法表的所有方法;2.子類方法的索引和父類對應(yīng)方法的索引一致。

        方法調(diào)用

        那么,動態(tài)綁定方法的調(diào)用過程如下:

        1.Java 棧中調(diào)用對應(yīng)指令,如?invokestatic #7 ;2.找到方法的調(diào)用者——Java 堆中的類;3.訪問該類對應(yīng)的方法表;4.找到方法的地址,調(diào)用方法。

        除此之外,JVM 還使用了內(nèi)聯(lián)緩存、方法內(nèi)聯(lián)的技術(shù)來優(yōu)化動態(tài)綁定方法的調(diào)用。內(nèi)聯(lián)緩存就是將動態(tài)綁定方法解析后的類型和目標方法緩存起來,下一次碰到相同類型直接使用。仍然是空間換時間的策略。

        總結(jié)

        至此,我們可以在腦中構(gòu)建出 JVM 運行字節(jié)碼的大致流程。從外部的字節(jié)碼結(jié)構(gòu)和解讀方法,到虛擬機加載字節(jié)碼流的過程,然后是虛擬機邏輯區(qū)域劃分和每部分的功能,以及 Java 棧中的計算過程,最后是具體方法調(diào)用指令的解析、調(diào)用機制。你可以查看以下文章進行回顧。

        淺談 JVM 1:一次編寫,到處運行

        淺談 JVM 2:如何閱讀字節(jié)碼

        淺談 JVM 3:指令集及其執(zhí)行

        淺談 JVM 4:類加載機制

        當然,JVM 相關(guān)的內(nèi)容不止這些。比如 Java 堆的內(nèi)存管理和回收機制、JVM 的啟動過程、JNI 調(diào)用機制等,我們還未涉及。

        另外,當初使用 Java 作為官方語言的 Android,其內(nèi)部在前期使用的 Dalvik 虛擬機和后來的 ART 虛擬機在結(jié)構(gòu)和運行字節(jié)碼上又有何不同?當下力推的 Kotlin 在虛擬機的執(zhí)行上和 Java 有什么不同嗎?

        我們有時間再聊。

        推薦

        工具:leetcode 的 VSCode、IDEA 插件。
        推薦原因:可以方便的瀏覽、提交算法題,和諧地在 IDE 中刷題。


        瀏覽 74
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            亚洲一区二区免费 | 欧美性插入 | 久青操 | 久久久久有精品国产白浆天美传媒 | 做爱视频免费观看网站 | 波多野结衣光棍影院 | 无码精品一区二区三区四区色 | 国产做受 91电影 | 2019偷偷鲁 | 青青色色网 |