【问题标题】:Can HotSpot inline lambda function calls?HotSpot 可以内联 lambda 函数调用吗?
【发布时间】:2017-10-24 23:38:07
【问题描述】:

考虑代码:

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

理论上,应该可以内联这段代码并消除间接函数调用,方法是先内联forEach方法,然后在内联forEach代码中内联lambda函数体。

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

【问题讨论】:

    标签: java optimization jvm hotspot


    【解决方案1】:

    你的 lambda 表达式被编译成一个普通的方法,而 JRE 将生成一个实现功能接口并调用该方法的类。在当前的 HotSpot 版本中,这个生成的类几乎就像一个普通的类一样工作,主要区别在于它可以调用 private 目标方法并且它不会被 ClassLoader 反向引用。

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

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

    【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2020-12-23
      • 2014-03-14
      • 2015-10-21
      • 2010-09-16
      • 1970-01-01
      • 1970-01-01
      • 2018-06-11
      • 2011-08-24
      相关资源
      最近更新 更多