淺談JVM系列之從匯編角度分析NullCheck
一個普通的virtual call
我們來分析一下在方法中調用list.add方法的例子:
public class TestNull { public static void main(String[] args) throws InterruptedException { List<String> list= new ArrayList(); list.add("www.flydean.com"); for (int i = 0; i < 10000; i++) { testMethod(list); } Thread.sleep(1000); } private static void testMethod(List<String> list) { list.get(0); } }
代碼很簡單,我們在循環中調用testMethod方法,而這個方法裡面又調用瞭list.get(0)方法,來獲取list的第一個參數。
單純的看testMethod,這個方法是有可能拋出NullPointerException的,但是從整體運行的角度來看,因為我們的list是有值的, 所以不會拋出異常。
使用JIT Watcher看看運行結果:
先看第二個和第三個紅框,我們可以看到代碼先做瞭參數類型的比較,然後對testMethod進行瞭優化,這裡還可以看到get方法是內聯到testMethod中的。
代碼優化的部分我們找到瞭,那麼異常處理呢?如果list為空,應該怎麼處理異常呢?
第一個紅框,大傢可以看到是一個隱式的異常處理,它重定向到1152b4f01這個地址。
第四個紅框就是這地址,表示的是異常處理的代碼。
普通方法中的null check
我們在上面的普通方法裡面加上一個null check:
public class TestNull1 { public static void main(String[] args) throws InterruptedException { List<String> list= new ArrayList(); list.add("www.flydean.com"); for (int i = 0; i < 10000; i++) { testMethod(list); } Thread.sleep(1000); } private static void testMethod(List<String> list) { if(list !=null ){ list.get(0); } } }
上面我們添加瞭一個list !=null的判斷。
運行看下結果:
相比較而言,我們可以看到,代碼其實沒有太多的變化,說明JIT在代碼優化的過程中,將null check優化掉瞭。
那麼null check到底在什麼地方呢? 看我標紅的第二個框,這裡是之前的異常處理區域,我們可以看到裡面有一個ifnull,表明這裡做瞭null check。
反優化的例子
上面的兩個例子,我們可以看出在virtual method中,JIT對null check進行瞭優化。接下來我們再看一個例子,在這個例子中,我們顯示的傳遞一個null給testMethod,然後再次循環testMethod,如下所示。
for (int i = 0; i < 10000; i++) { testMethod(list); } Thread.sleep(1000); testMethod(null); for (int i = 0; i < 10000; i++) { testMethod(list); }
我們看下JIT的結果:
看下結果有什麼不同呢?
第一,ifnull現在是顯示調用的,並不包含在隱式異常中。
第二,隱式異常也不見瞭,因為使用顯示的ifnull。
以上就是淺談JVM系列之從匯編角度分析NullCheck的詳細內容,更多關於JVM系列之從匯編角度分析NullCheck的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- 一篇文章掌握Java Thread的類及其常見方法
- 詳談jvm線程棧空間內存分配位置
- Java線程中的常見方法(start方法和run方法)
- Java中保證線程順序執行的操作代碼
- 淺談JVM之使用JFR解決內存泄露