1. 程式人生 > >JVM系列之:JIT中的Virtual Call介面

JVM系列之:JIT中的Virtual Call介面

[toc] # 簡介 上一篇文章我們講解了Virtual Call的定義並舉例分析了Virtual Call在父類和子類中的優化。 JIT對類可以進行優化,那麼對於interface可不可以做同樣的優化麼? 一起來看看吧。 # 最常用的介面List List應該是大家最最常用的介面了,我想這個大家應該不會反駁。 ~~~java public interface List extends Collection { ~~~ 今天我們就拿List來做例子,體驗一下JIT優化介面的奧祕。 還是上程式碼,要分析的程式碼如下: ~~~java public class TestVirtualListCall { public static void main(String[] args) throws InterruptedException { List list=new ArrayList<>(); for (int i = 0; i < 10000; i++) { doWithVMethod(list); } Thread.sleep(1000); } public static void doWithVMethod(List list) { list.add("www.flydean.com"); } } ~~~ > 如果在命令列執行,大家記得在執行時新增引數-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:-Inline 直接看JIT Watcher的結果: ![](https://img-blog.csdnimg.cn/20200630104308633.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70) 我們可以看到JIT中先對ArrayList的實現類做了一個比較。 然後呼叫的是invokeinterface,但是其本質還是invokevirtual,並且我們可以看到這個呼叫是被優化過了:optimized virtual call。 # 多個List的呼叫 同樣的,我們可以測試一下多個list子類的情況下怎麼呼叫: ~~~java public class TestVirtualListCall2 { public static void main(String[] args) throws InterruptedException { List[] lists=new List[]{new ArrayList<>(),new LinkedList<>()}; for (int i = 0; i < 10000; i++) { doWithVMethod(lists[i%2]); } Thread.sleep(1000); } public static void doWithVMethod(List list) { list.add("www.flydean.com"); } } ~~~ 同樣,使用JIT Watcher來執行: ![](https://img-blog.csdnimg.cn/20200630104909436.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70) 我們可以看到JIT做了兩次物件型別的比較,然後對兩個invokeinterface都做了優化。 結果和我們的父類子類結果是一樣的。 # 不一樣的List呼叫 上面我們在做多個list呼叫的時候,是輪循著來呼叫的,如果我們先呼叫ArrayList的方法,再呼叫LinkedList的方法,會有什麼不同呢? 一起來看看。 ~~~java public class TestVirtualListCall3 { public static void main(String[] args) throws InterruptedException { List list1 = new ArrayList<>(); List list2 = new LinkedList<>(); for (int i = 0; i < 10000; i++) { doWithVMethod(list1); } Thread.sleep(1000); for (int i = 0; i < 10000; i++) { doWithVMethod(list2); } Thread.sleep(1000); } public static void doWithVMethod(List list) { list.add("www.flydean.com"); } } ~~~ 上面我們先迴圈ArrayList,然後再迴圈LinkedList。 看下結果有什麼不同: ![](https://img-blog.csdnimg.cn/20200630111901141.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70) 可以看到,JIT先比較了ArrayList,然後只做了一次方法的優化。 也就是說LinkedList的呼叫是沒有進行程式碼優化的。 上面的結果是在C2編譯器下,也就是level4的編譯水平下解析的。 我們看下如果在C1編譯器下,也就是Level3編譯水平下有什麼不同。 ![](https://img-blog.csdnimg.cn/20200630112131810.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70) 可以看到C1編譯下,所有的invokeinterface都沒有進行編譯優化,只有在C2編譯下,才會進行優化。 > 不同的JVM版本可能優化方式不一樣。大家可以自行實驗。 # 總結 本文用例項展示了Virtual Call在interface上面的優化使用。 感興趣的朋友,可以一起討論。 > 本文作者:flydean程式那些事 > > 本文連結:[http://www.flydean.com/jvm-virtual-call-interface/](http://www.flydean.com/jvm-virtual-call-interface/) > > 本文來源:flydean的部落格 > > 歡迎關注我的公眾號:程式那些事,更多精彩等著您!