我基本上了解JVM可以在其内联一个方法后执行 的某些操作,例如scalar replacement
,escape analysis
或lock elision
等(我承认不知道所有人)。但是,如果方法太大而无法内联怎么办? JVM是否可以对这些方法进行任何优化?我在想loop unrolling
是一个...
有人知道这个主题可能会有所启发吗?
答案 0 :(得分:3)
内联是一种超级优化,它扩大了许多其他优化的范围:常见子表达式消除,常量传播,标量替换等。 非内联方法是一个黑匣子-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中进行标量替换的一个明显要求是对象构造函数及其所有调用方法都已内联,但是调用者本身并不需要内嵌。
答案 1 :(得分:0)
Range check elimination将是不需要内联的优化示例。请查看OpenJDK Wiki的Performance Techniques部分以获取更多示例,PerformanceTacticIndex中列出了一长串优化列表。