JVM 非内联方法优化
JVM non-inlined methods optimizations
我基本上知道 JVM 可以做的一些事情 在 它内联一个方法之后,比如 scalar replacement
、escape analysis
或 lock elision
等等(我承认我不认识所有人)。但是,如果方法太大而无法内联怎么办? JVM 是否可以对这些方法进行任何优化?我在想 loop unrolling
会是一个...
任何了解该主题的人都可以提供一些线索?
Range check elimination would be an example of optimisation that doesn't require inlining. Take a look at Performance Techniques section of OpenJDK wiki for more examples, a long list of optimisations is listed in PerformanceTacticIndex.
内联是一种超级优化,它拓宽了许多其他优化的上下文:公共子表达式消除、常量传播、标量替换等。
非内联方法是一个黑盒子——JVM 不知道这样的方法是否修改了对象字段、抛出异常、注册它破坏等等。
内联有助于其他优化,但这并不意味着其他优化没有内联就无法工作。 JIT 编译单元是一种方法,JVM 可以将几乎所有的优化应用到其作用域内的一个大的非内联方法上。想象一下,您通过在源代码中手动内联所有被调用者来创建一个非常大的方法。所以,无论是手动内联还是自动内联,结果控制流/数据流图都大致相同,所以JIT能够处理这两种情况。
特别是,逃逸分析将在大方法中完美运行; allocations 和 locks 如果不逃避这个方法,还是可以去掉的。
让我用以下 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 中发生标量替换的一个明显要求是对象构造函数及其所有调用的方法都是内联的,但调用者本身不需要内联。
我基本上知道 JVM 可以做的一些事情 在 它内联一个方法之后,比如 scalar replacement
、escape analysis
或 lock elision
等等(我承认我不认识所有人)。但是,如果方法太大而无法内联怎么办? JVM 是否可以对这些方法进行任何优化?我在想 loop unrolling
会是一个...
任何了解该主题的人都可以提供一些线索?
Range check elimination would be an example of optimisation that doesn't require inlining. Take a look at Performance Techniques section of OpenJDK wiki for more examples, a long list of optimisations is listed in PerformanceTacticIndex.
内联是一种超级优化,它拓宽了许多其他优化的上下文:公共子表达式消除、常量传播、标量替换等。 非内联方法是一个黑盒子——JVM 不知道这样的方法是否修改了对象字段、抛出异常、注册它破坏等等。
内联有助于其他优化,但这并不意味着其他优化没有内联就无法工作。 JIT 编译单元是一种方法,JVM 可以将几乎所有的优化应用到其作用域内的一个大的非内联方法上。想象一下,您通过在源代码中手动内联所有被调用者来创建一个非常大的方法。所以,无论是手动内联还是自动内联,结果控制流/数据流图都大致相同,所以JIT能够处理这两种情况。
特别是,逃逸分析将在大方法中完美运行; allocations 和 locks 如果不逃避这个方法,还是可以去掉的。
让我用以下 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 中发生标量替换的一个明显要求是对象构造函数及其所有调用的方法都是内联的,但调用者本身不需要内联。