考虑的代码:可以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