考慮的代碼:可以HotSpot內聯lambda函數調用?
someList.forEach(x -> System.out.format("element %s", x));
理論上,應該可以內聯這個代碼和消除由第一內聯forEach
方法,然後內聯lambda函數體中內聯代碼forEach
間接函數調用。
HotSpot能夠執行此優化嗎?在特定情況下是否執行了哪些限制?
考慮的代碼:可以HotSpot內聯lambda函數調用?
someList.forEach(x -> System.out.format("element %s", x));
理論上,應該可以內聯這個代碼和消除由第一內聯forEach
方法,然後內聯lambda函數體中內聯代碼forEach
間接函數調用。
HotSpot能夠執行此優化嗎?在特定情況下是否執行了哪些限制?
你的lambda表達式被編譯成普通方法,而JRE將生成一個滿足功能接口並調用該方法的類。在當前的HotSpot版本中,這個生成的類幾乎像普通類一樣工作,主要區別在於它可以調用private
目標方法,並且它不會被ClassLoader
反向引用。
這些屬性都不影響優化,最終只有一個普通的方法調用鏈。使用當前JVM的代碼最大的障礙是內聯限制,即最大深度(默認爲9個嵌套方法IIRC)和最大結果代碼大小。其中一些默認值非常舊,自上次定義以來未修改。但是,這種限制可能會影響非常長的流管道,而不是像普通的forEach
這樣的用例。
所以一般的答案是HotSpot能夠執行這樣的優化,但是像所有的優化一樣,它會讓你的代碼運行幾次,然後再確定它是否是性能關鍵並執行優化,如果所以。
這實際上很容易證明。下面是一些很簡單的代碼:
for (int i = 0; i < 100_000; ++i) {
Stream.of(1, 2, 3, 4)
.map(x -> x * 2)
.collect(Collectors.toList());
}
當我編譯此我可以看到,對於λ表達式(經由javap
)將所生成的解加糖方法稱爲:lambda$main$0
(在JDK-9,但這並不很重要)。
,然後我可以簡單地運行該代碼:
java -XX:-TieredCompilation
-XX:CICompilerCount=1
-XX:+UnlockDiagnosticVMOptions
-XX:+PrintCompilation
-XX:+PrintInlining
-XX:CompileCommand="print, *.lambda"
InlineLambdaTest
> inline.txt
並查看文件有這樣的臺詞:
Inline::lambda$main$0 (10 bytes) inline (hot)
,因此內聯這種方法的工作通常的方式。請注意,將有更多的行以...lambda...
開頭,因爲在內部還有很多其他地方使用lambda表達式,這些地方也被認爲很熱。
另請參見[如何編譯Java lambda函數?](https://stackoverflow.com/q/16827262/2711488) – Holger
您確實記得:'intx MaxInlineLevel = 9'。 – Eugene