您好,登錄后才能下訂單哦!
這篇文章主要介紹“Java中的方法內聯怎么用”,在日常操作中,相信很多人在Java中的方法內聯怎么用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java中的方法內聯怎么用”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
例如有下面的原始代碼:
static class B { int value; final int get() { return value; } } public void foo() { y = b.get(); // ...do stuff... z = b.get(); sum = y + z; }
我們首先要進行的就是方法內聯,主要有下面兩個目的:
去除方法調用的成本,如查找方法版本、建立棧幀。
為其他優化建立良好基礎。
內聯后代碼如下:
public void foo() { y = b.value; // ...do stuff... z = b.value; sum = y + z; }
后續,還可以進行冗余訪問消除、復寫傳播、無用代碼消除等優化操作。
方法內聯是編譯器最重要的優化手段,如果沒有內聯,多數其他優化都無法有效進行。例如下面這個例子:
public static void foo(Object obj){ if (obj != null) { System.out.println("do something"); } } public static void testInline(String[] args) { Object obj = null; foo(obj); }
testInline()
方法里其實全都是無用的代碼,但是如果不做方法內聯,就無法發現任何 Dead Code 的存在,因為分開看的話兩個方法里面的操作可能都有意義。
在 JVM 中,只有非虛方法,也就是使用invokespecial
指令調用的私有方法、實例構造器、父類方法和使用invokestatic
指令調用的靜態方法才會在編譯器進行解析。
而其他虛方法被invokevirtual
指令調用,在調用時必須進行方法接收者的多態選擇。對于一個虛方法,編譯器靜態地去做內聯的時候很難確定應該使用哪個方法版本,這就造成了方法內聯的困難。
首先,JVM 引入了一種名為類型繼承關系分析 CHA 的技術,這種技術用于在已加載的類中,確定某個接口是否有多于一種的實現、某個類是否存在子類、某個子類是否覆蓋了父類的某個虛方法等信息。
編譯器在進行內聯時會分不同情況采取不同處理:
如果是非虛方法,那么就直接進行內聯。
如果是虛方法,那么向 CHA 查詢是否有多個目標版本可供選擇。
如果只有一個版本,就直接內聯,稱為守護內聯。但由于 Java 程序動態連接,不知道什么時候就會加載到新的類型而改變 CHA 的結論,所以要留好逃生門,假如程序后續執行中加載了導致繼承關系發生變化的新類,那么必須拋棄已經編譯的代碼,退回到解釋狀態進行執行,或者重新編譯。
如果有多個版本可供選擇,那即時編譯器使用內聯緩存來縮減方法調用的開銷。內聯緩存是一個建立在目標方法正常入口之前的緩存。在未發生方法調用時,內聯緩存為空。第一次調用發生后,緩存記錄下方法接收者的版本信息,并且在每次進行調用前都檢查版本。
如果每次調用的方法接收者版本是一樣的,那稱為單態內聯緩存,通過緩存來調用,相比不內聯只多了一次類型判斷的開銷。如果出現方法接收者不一致的情況,就退化為超多態內聯緩存,開銷相當于真正查找虛方法表來進行方法分派。當緩存未命中的時候,大多數JVM的實現時退化成超多態內聯緩存,也有一些JVM選擇重寫單態內聯緩存,就是更新緩存為新的版本。這樣做的好處是以后還可能會命中,壞處是可能白白浪費一個寫的開銷。
到此,關于“Java中的方法內聯怎么用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。