亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

淺談JVM系列之JIT中的Virtual Call

 更新時間:2021年06月03日 08:53:21   作者:flydean  
什么是Virtual Call?Virtual Call在java中的實現(xiàn)是怎么樣的?Virtual Call在JIT中有沒有優(yōu)化?所有的答案看完這篇文章就明白了。

Virtual Call和它的本質(zhì)

有用過PrintAssembly的朋友,可能會在反編譯的匯編代碼中發(fā)現(xiàn)有些方法調(diào)用的說明是invokevirtual,實際上這個invokevirtual就是Virtual Call。

Virtual Call是什么呢?

面向?qū)ο蟮木幊陶Z言基本上都支持方法的重寫,我們考慮下面的情況:

private static class CustObj
{
    public void methodCall()
    {
        if(System.currentTimeMillis()== 0){
            System.out.println("CustObj is very good!");
        }
    }
}
private static class CustObj2 extends  CustObj
{
    public final void methodCall()
    {
        if(System.currentTimeMillis()== 0){
            System.out.println("CustObj2 is very good!");
        }
    }
}

我們定義了兩個類,CustObj是父類CustObj2是子類。然后我們通一個方法來調(diào)用他們:

public static void doWithVMethod(CustObj obj)
{
    obj.methodCall();
}

因為doWithVMethod的參數(shù)類型是CustObj,但是我們同樣也可以傳一個CustObj2對象給doWithVMethod。

怎么傳遞這個參數(shù)是在運行時決定的,我們很難在編譯的時候判斷到底該如何執(zhí)行。

那么JVM會怎么處理這個問題呢?

答案就是引入VMT(Virtual Method Table),這個VMT存儲的是該class對象中所有的Virtual Method。

然后class的實例對象保存著一個VMT的指針,執(zhí)行VMT。

程序運行的時候首先加載實例對象,然后通過實例對象找到VMT,通過VMT再找到對應的方法地址。

Virtual Call和classic call

Virtual Call意思是調(diào)用方法的時候需要依賴不同的實例對象。而classic call就是直接指向方法的地址,而不需要通過VMT表的轉(zhuǎn)換。

所以classic call通常會比Virtual Call要快。

那么在java中是什么情況呢?

在java中除了static, private和構(gòu)造函數(shù)之外,其他的默認都是Virtual Call。

Virtual Call優(yōu)化單實現(xiàn)方法的例子

有些朋友可能會有疑問了,java中其他方法默認都是Virtual Call,那么如果只有一個方法的實現(xiàn),性能不會受影響嗎?

不用怕,JIT足夠智能,可以檢測到這種情況,在這種情況下JIT會對Virtual Call進行優(yōu)化。

接下來,我們使用JIT Watcher來進行Assembly代碼的分析。

要運行的代碼如下:

public class TestVirtualCall {

    public static void main(String[] args) throws InterruptedException {
        CustObj obj = new CustObj();
        for (int i = 0; i < 10000; i++)
        {
            doWithVMethod(obj);
        }
        Thread.sleep(1000);
    }

    public static void doWithVMethod(CustObj obj)
    {
        obj.methodCall();
    }

    private static class CustObj
    {
        public void methodCall()
        {
            if(System.currentTimeMillis()== 0){
                System.out.println("CustObj is very good!");
            }
        }
    }
}

上面的例子中我們只定義了一個類的方法實現(xiàn)。

在JIT Watcher的配置中,我們禁用inline,以免inline的結(jié)果對我們的分析進行干擾。

如果你不想使用JIT Watcher,那么可以在運行是添加參數(shù)-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:-Inline, 這里使用JIT Watcher是為了方便分析。

好了運行代碼:

運行完畢,界面直接定位到我們的JIT編譯代碼的部分,如下圖所示:

obj.methodCall相對應的byteCode中,大家可以看到第二行就是invokevirtual,和它對應的匯編代碼我也在最右邊標明了。

大家可以看到在invokevirtual methodCall的最下面,已經(jīng)寫明了optimized virtual_call,表示這個方法已經(jīng)被JIT優(yōu)化過了。

接下來,我們開啟inline選項,再運行一次:

大家可以看到methodCall中的System.currentTimeMillis已經(jīng)被內(nèi)聯(lián)到methodCall中了。

因為內(nèi)聯(lián)只會發(fā)生在classic calls中,所以也側(cè)面說明了methodCall方法已經(jīng)被優(yōu)化了。

Virtual Call優(yōu)化多實現(xiàn)方法的例子

上面我們講了一個方法的實現(xiàn),現(xiàn)在我們測試一下兩個方法的實現(xiàn):

public class TestVirtualCall2 {

    public static void main(String[] args) throws InterruptedException {
        CustObj obj = new CustObj();
        CustObj2 obj2 = new CustObj2();
        for (int i = 0; i < 10000; i++)
        {
            doWithVMethod(obj);
            doWithVMethod(obj2);

        }
        Thread.sleep(1000);
    }

    public static void doWithVMethod(CustObj obj)
    {
        obj.methodCall();
    }

    private static class CustObj
    {
        public void methodCall()
        {
            if(System.currentTimeMillis()== 0){
                System.out.println("CustObj is very good!");
            }
        }
    }
    private static class CustObj2 extends  CustObj
    {
        public final void methodCall()
        {
            if(System.currentTimeMillis()== 0){
                System.out.println("CustObj2 is very good!");
            }
        }
    }
}

上面的例子中我們定義了兩個類CustObj和CustObj2。

再次運行看下結(jié)果,同樣的,我們還是禁用inline。

大家可以看到結(jié)果中,首先對兩個對象做了cmp,然后出現(xiàn)了兩個優(yōu)化過的virtual call。

這里比較的作用就是找到兩個實例對象中的方法地址,從而進行優(yōu)化。

那么問題來了,兩個對象可以優(yōu)化,三個對象,四個對象呢?

我們選擇三個對象來進行分析:

public class TestVirtualCall4 {

    public static void main(String[] args) throws InterruptedException {
        CustObj obj = new CustObj();
        CustObj2 obj2 = new CustObj2();
        CustObj3 obj3 = new CustObj3();
        for (int i = 0; i < 10000; i++)
        {
            doWithVMethod(obj);
            doWithVMethod(obj2);
            doWithVMethod(obj3);

        }
        Thread.sleep(1000);
    }

    public static void doWithVMethod(CustObj obj)
    {
        obj.methodCall();
    }

    private static class CustObj
    {
        public void methodCall()
        {
            if(System.currentTimeMillis()== 0){
                System.out.println("CustObj is very good!");
            }
        }
    }
    private static class CustObj2 extends  CustObj
    {
        public final void methodCall()
        {
            if(System.currentTimeMillis()== 0){
                System.out.println("CustObj2 is very good!");
            }
        }
    }
    private static class CustObj3 extends  CustObj
    {
        public final void methodCall()
        {
            if(System.currentTimeMillis()== 0){
                System.out.println("CustObj3 is very good!");
            }
        }
    }
}

運行代碼,結(jié)果如下:

總結(jié)

本文介紹了Virtual Call和它在java代碼中的使用,并在匯編語言的角度對其進行了一定程度的分析。

以上就是淺談JVM系列之JIT中的Virtual Call的詳細內(nèi)容,更多關(guān)于JVM系列之JIT中的Virtual Call的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳細介紹idea如何設置類頭注釋和方法注釋(圖文)

    詳細介紹idea如何設置類頭注釋和方法注釋(圖文)

    本篇文章主要介紹了idea如何設置類頭注釋和方法注釋(圖文),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • SiteMesh如何結(jié)合Freemarker及velocity使用

    SiteMesh如何結(jié)合Freemarker及velocity使用

    這篇文章主要介紹了SiteMesh如何結(jié)合Freemarker及velocity使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-10-10
  • springBoot集成mybatis 轉(zhuǎn)換為 mybatis-plus方式

    springBoot集成mybatis 轉(zhuǎn)換為 mybatis-plus方式

    這篇文章主要介紹了springBoot集成mybatis 轉(zhuǎn)換為 mybatis-plus方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 23種設計模式(12)java模版方法模式

    23種設計模式(12)java模版方法模式

    這篇文章主要為大家詳細介紹了23種設計模式之java模版方法模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • 五種JAVA GUI布局管理的方式

    五種JAVA GUI布局管理的方式

    這篇文章主要介紹了JAVA幾種GUI布局管理的相關(guān)知識,文中代碼非常詳細,幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-06-06
  • Java List中數(shù)據(jù)的去重

    Java List中數(shù)據(jù)的去重

    今天小編就為大家分享一篇關(guān)于Java List中數(shù)據(jù)的去重,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • 解析springcloud中的Hystrix

    解析springcloud中的Hystrix

    Hystrix是一個用于處理分布式系統(tǒng)的延遲和容錯的開源庫,在分布式系統(tǒng)里,許多依賴不可避免的會調(diào)用失敗,比如超時、異常等。這篇文章主要介紹了springcloud中的Hystrix,需要的朋友可以參考下
    2020-10-10
  • Mybatis中<if>和<choose>的區(qū)別及“=”判斷方式

    Mybatis中<if>和<choose>的區(qū)別及“=”判斷方式

    這篇文章主要介紹了Mybatis中<if>和<choose>的區(qū)別及“=”判斷方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Arthas在線java進程診斷工具在線調(diào)試神器詳解

    Arthas在線java進程診斷工具在線調(diào)試神器詳解

    Arthas是 Alibaba 開源的Java診斷工具,深受開發(fā)者喜愛。這篇文章主要介紹了Arthas在線java進程診斷工具 在線調(diào)試神器,需要的朋友可以參考下
    2021-11-11
  • Java的ArrayList擴容源碼解析

    Java的ArrayList擴容源碼解析

    這篇文章主要介紹了Java的ArrayList擴容源碼解析,通過動態(tài)擴容,ArrayList能夠在添加元素時保持高效的性能,擴容操作是有一定開銷的,但由于擴容的時間復雜度為O(n),其中n是當前元素個數(shù),所以平均情況下,每次添加元素的時間復雜度仍然是O(1),需要的朋友可以參考下
    2024-01-01

最新評論