HotSpot 可以内联 lambda 函数调用吗?
Can HotSpot inline lambda function calls?
考虑代码:
someList.forEach(x -> System.out.format("element %s", x));
理论上,应该可以通过先内联 forEach
方法,然后在内联 forEach
代码中内联 lambda 函数体来内联此代码并消除间接函数调用。
HotSpot 是否能够执行此优化?在特定情况下是否执行它有哪些限制?
您的 lambda 表达式被编译成一个普通方法,而 JRE 将生成一个 class 实现功能接口并调用该方法。在当前的 HotSpot 版本中,这个生成的 class 几乎像普通的 class 一样工作,主要区别在于它可以调用 private
目标方法并且它不被 ClassLoader
.
None 这些属性阻碍了优化,最后,您只有一连串的普通方法调用。当前 JVM 的此类代码的最大障碍是内联限制,关于最大深度(默认为九个嵌套方法 IIRC)和最大结果代码大小。其中一些默认值非常旧,自上次定义以来没有修改过。但是,此类限制可能会影响非常长的流管道,而不是像您的普通 forEach
.
这样的用例
所以一般的答案是 HotSpot 能够执行此类优化,但与所有优化一样,它会让您的代码 运行 几次,然后再确定它是否对性能至关重要并执行优化(s),如果是的话。
这其实很容易证明。这是一些非常简单的代码:
for (int i = 0; i < 100_000; ++i) {
Stream.of(1, 2, 3, 4)
.map(x -> x * 2)
.collect(Collectors.toList());
}
当我编译它时,我可以看到为 lambda 表达式生成的脱糖方法(通过 javap
)被调用:lambda$main[=14=]
(在 jdk-9 中,但是这无关紧要)。
然后我可以简单地运行这段代码:
java -XX:-TieredCompilation
-XX:CICompilerCount=1
-XX:+UnlockDiagnosticVMOptions
-XX:+PrintCompilation
-XX:+PrintInlining
-XX:CompileCommand="print, *.lambda"
InlineLambdaTest
> inline.txt
查看文件中有这样几行:
Inline::lambda$main[=12=] (10 bytes) inline (hot)
所以这种方法的内联以通常的方式工作。请注意,将有更多以 ...lambda...
开头的行,因为内部还有许多其他地方使用 lambda 表达式,这些地方也被认为是热门的。
考虑代码:
someList.forEach(x -> System.out.format("element %s", x));
理论上,应该可以通过先内联 forEach
方法,然后在内联 forEach
代码中内联 lambda 函数体来内联此代码并消除间接函数调用。
HotSpot 是否能够执行此优化?在特定情况下是否执行它有哪些限制?
您的 lambda 表达式被编译成一个普通方法,而 JRE 将生成一个 class 实现功能接口并调用该方法。在当前的 HotSpot 版本中,这个生成的 class 几乎像普通的 class 一样工作,主要区别在于它可以调用 private
目标方法并且它不被 ClassLoader
.
None 这些属性阻碍了优化,最后,您只有一连串的普通方法调用。当前 JVM 的此类代码的最大障碍是内联限制,关于最大深度(默认为九个嵌套方法 IIRC)和最大结果代码大小。其中一些默认值非常旧,自上次定义以来没有修改过。但是,此类限制可能会影响非常长的流管道,而不是像您的普通 forEach
.
所以一般的答案是 HotSpot 能够执行此类优化,但与所有优化一样,它会让您的代码 运行 几次,然后再确定它是否对性能至关重要并执行优化(s),如果是的话。
这其实很容易证明。这是一些非常简单的代码:
for (int i = 0; i < 100_000; ++i) {
Stream.of(1, 2, 3, 4)
.map(x -> x * 2)
.collect(Collectors.toList());
}
当我编译它时,我可以看到为 lambda 表达式生成的脱糖方法(通过 javap
)被调用:lambda$main[=14=]
(在 jdk-9 中,但是这无关紧要)。
然后我可以简单地运行这段代码:
java -XX:-TieredCompilation
-XX:CICompilerCount=1
-XX:+UnlockDiagnosticVMOptions
-XX:+PrintCompilation
-XX:+PrintInlining
-XX:CompileCommand="print, *.lambda"
InlineLambdaTest
> inline.txt
查看文件中有这样几行:
Inline::lambda$main[=12=] (10 bytes) inline (hot)
所以这种方法的内联以通常的方式工作。请注意,将有更多以 ...lambda...
开头的行,因为内部还有许多其他地方使用 lambda 表达式,这些地方也被认为是热门的。