欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談JVM系列之JIT中的Virtual Call

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

Virtual Call和它的本質(zhì)

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

Virtual Call是什么呢?

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

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!");
        }
    }
}

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

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

因?yàn)閐oWithVMethod的參數(shù)類(lèi)型是CustObj,但是我們同樣也可以傳一個(gè)CustObj2對(duì)象給doWithVMethod。

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

那么JVM會(huì)怎么處理這個(gè)問(wèn)題呢?

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

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

程序運(yùn)行的時(shí)候首先加載實(shí)例對(duì)象,然后通過(guò)實(shí)例對(duì)象找到VMT,通過(guò)VMT再找到對(duì)應(yīng)的方法地址。

Virtual Call和classic call

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

所以classic call通常會(huì)比Virtual Call要快。

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

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

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

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

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

接下來(lái),我們使用JIT Watcher來(lái)進(jìn)行Assembly代碼的分析。

要運(yùn)行的代碼如下:

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!");
            }
        }
    }
}

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

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

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

好了運(yùn)行代碼:

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

obj.methodCall相對(duì)應(yīng)的byteCode中,大家可以看到第二行就是invokevirtual,和它對(duì)應(yīng)的匯編代碼我也在最右邊標(biāo)明了。

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

接下來(lái),我們開(kāi)啟inline選項(xiàng),再運(yùn)行一次:

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

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

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

上面我們講了一個(gè)方法的實(shí)現(xiàn),現(xiàn)在我們測(cè)試一下兩個(gè)方法的實(shí)現(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!");
            }
        }
    }
}

上面的例子中我們定義了兩個(gè)類(lèi)CustObj和CustObj2。

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

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

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

那么問(wèn)題來(lái)了,兩個(gè)對(duì)象可以?xún)?yōu)化,三個(gè)對(duì)象,四個(gè)對(duì)象呢?

我們選擇三個(gè)對(duì)象來(lái)進(jìn)行分析:

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!");
            }
        }
    }
}

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

總結(jié)

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

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

相關(guān)文章

  • 詳細(xì)介紹idea如何設(shè)置類(lèi)頭注釋和方法注釋(圖文)

    詳細(xì)介紹idea如何設(shè)置類(lèi)頭注釋和方法注釋(圖文)

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

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

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

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

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

    23種設(shè)計(jì)模式(12)java模版方法模式

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

    五種JAVA GUI布局管理的方式

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

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

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

    解析springcloud中的Hystrix

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

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

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

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

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

    Java的ArrayList擴(kuò)容源碼解析

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

最新評(píng)論