HotSpot 可以内联 lambda 函数调用吗?

问题描述 投票:0回答:2

考虑代码:

someList.forEach(x -> System.out.format("element %s", x));

理论上,应该可以通过首先内联

forEach
方法,然后在内联
forEach
代码中内联 lambda 函数体来内联此代码并消除间接函数调用。

HotSpot 能够执行此优化吗?在特定情况下是否执行有哪些限制?

java optimization jvm jvm-hotspot
2个回答
7
投票

您的 lambda 表达式被编译为普通方法,而 JRE 将生成一个实现功能接口并调用该方法的类。在当前的 HotSpot 版本中,这个生成的类几乎像普通类一样工作,主要区别在于它可以调用

private
目标方法并且它不会被
ClassLoader
反向引用。

这些属性都不会妨碍优化,最终,你只有一串普通的方法调用。当前 JVM 中此类代码的最大障碍是内联限制,涉及最大深度(默认为九个嵌套方法 IIRC)和最大结果代码大小。其中一些默认值非常古老,并且自上次定义以来未进行修订。然而,这样的限制可能会影响很长的流管道,而不是像您的普通

forEach
这样的用例。

因此,一般答案是 HotSpot 能够执行此类优化,但与所有优化一样,它会让您的代码运行几次,然后确定它是否对性能至关重要并执行优化(如果是)。


6
投票

这实际上很容易证明。这是一些非常简单的代码:

 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$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 表达式,这些表达式也被认为是热门的。

© www.soinside.com 2019 - 2024. All rights reserved.