我基本上知道 JVM 内联方法后可以做的一些事情,例如标量替换
、转义分析
或lock elision
等(我承认我不知道所有这些)。但是如果方法太大而无法内联怎么办? JVM 可以对这些方法进行优化吗?我认为循环展开
将是一个......
任何了解这个主题的人都可以提供一些线索吗?
最佳答案
内联是一种 super 优化,它拓宽了许多其他优化的范围:公共(public)子表达式消除、常量传播、标量替换等。 非内联方法是一个黑匣子 - 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 中进行标量替换的一个明显要求是对象构造函数及其所有调用的方法都是内联的,但调用者本身不需要内联。
关于java - JVM 非内联方法优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52427394/