【问题标题】:JVM non-inlined methods optimizationsJVM 非内联方法优化
【发布时间】:2018-09-24 00:51:19
【问题描述】:

我基本上知道 JVM 可以在 内联一个方法之后做一些事情,例如 scalar replacement、escape analysis 或 lock elision 等(我承认我不知道所有这些) .但是如果一个方法太大而不能内联怎么办? JVM 是否可以对这些方法进行任何优化?我在想loop unrolling 会是一个......

知道这个主题的人可能会有所启发吗?

【问题讨论】:

  • “关于那些方法”? “太大而无法内联”的方法仍然可以得到优化。更有趣的部分是该方法的调用者,或者调用者和被调用者之间的交互。
  • @Holger 我理解它可以,它不像它永远在解释模式下运行......
  • 我不太明白这个问题。 JIT 编译单元是一种方法。 JVM 可以将几乎所有的优化应用到一个大的非内联方法上,尽管优化的范围会受到这个方法的范围的限制。
  • 例如逃逸分析将在这个大方法中完美运行;如果不转义这个方法,分配和锁仍然可以被消除。
  • @apangin 我认为只有在方法被内联时才会进行转义分析,不是吗?我只尝试过一次查看scalar replacement,除非内联方法,否则不会发生这种情况,因此我认为只有在内联发生时才会发生其他优化

标签: java jvm jit


【解决方案1】:

内联是一种超级优化,它为许多其他优化拓宽了上下文:公共子表达式消除、常量传播、标量替换等。 非内联方法是一个黑匣子——JVM 不知道这种方法是否修改对象字段、抛出异常、注册它的损坏等等。

内联有助于其他优化,但这并不意味着没有内联其他优化就无法工作。 JIT 编译单元是一种方法,JVM 可以在其范围内对一个大的非内联方法进行几乎所有的优化。想象一下,您通过在源代码中手动内联所有被调用者来创建一个非常大的方法。因此,无论内联是手动还是自动完成,结果控制流/数据流图都将大致相同,因此 JIT 将能够处理这两种情况。

特别是,逃逸分析将在大方法中完美运行;如果不转义这个方法,分配和锁仍然可以被消除。

让我用下面的 JMH 基准来证明这一点。使用-prof gc 运行它,以确保在内联和非内联情况下都没有分配对象。

@State(Scope.Benchmark)
public class Inline {
    double x = 111;
    double y = 222;

    @Benchmark
    public double inline() {
        return doInline(x, y);

    }

    @Benchmark
    public double noinline() {
        return dontInline(x, y);
    }

    @CompilerControl(CompilerControl.Mode.INLINE)
    private double doInline(double a, double b) {
        return new Vector2D(a, b).norm();
    }

    @CompilerControl(CompilerControl.Mode.DONT_INLINE)
    private double dontInline(double a, double b) {
        return new Vector2D(a, b).norm();
    }

    static class Vector2D {
        private final double x;
        private final double y;

        public Vector2D(double x, double y) {
            this.x = x;
            this.y = y;
        }

        public double norm() {
            return Math.sqrt(x * x + y * y);
        }
    }
}

在 HotSpot 中发生标量替换的一个明显要求是对象构造函数及其所有被调用的方法都是内联的,但调用者本身不需要内联。

【讨论】:

  • 您是否知道禁用内联实际上会使性能变差的任何特殊情况?
  • @SergeyTsypanov 禁用内联几乎总是会使性能变差...不确定我是否理解这个问题。
  • 让我改述一下。我在这里stackoverflow.com/questions/63397711/… 正在查看您对我的问题的回答,我想到了,当我们禁用内联时可能会出现这种情况,因此代码没有像往常一样优化。由于缺少/削弱优化,我们现在的配置文件与正常不同,即使用-XX:MaxInlineLevel=0 收集的配置文件中的热点可能与“正常”配置文件中突出显示的热点不同
  • @SergeyTsypanov 是的,这绝对有可能。
【解决方案2】:

Range check elimination 是一个不需要内联的优化示例。更多示例请查看 OpenJDK wiki 的 Performance Techniques 部分,PerformanceTacticIndex 中列出了很长的优化列表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-04
    • 2011-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-10
    • 2013-09-24
    相关资源
    最近更新 更多