在通过类变量调用时,Java 9中的Class.cast和Class.isInstance方法实际上是内在的吗?

Dmi*_*kiy 3 java performance microbenchmark java-9

我一直在寻找通过Java的9个新特性的方法和发现,现在的方法Class.cast 是内在的与太一起Class.isInstance.

我做了简单的基准来检查:

@BenchmarkMode(Mode.Throughput)
@Fork(1)
@State(Scope.Thread)
@Warmup(iterations = 10, time = 1, batchSize = 1000)
@Measurement(iterations = 20, time = 1, batchSize = 1000)
public class Casting {

    public Object msg;
    public Class<String> type;

    @Setup
    public void setup(BenchmarkParams params) {
        type = String.class;
        msg = "123";
    }

    @Benchmark
    public boolean isInstanceMethod() {
        return type.isInstance(msg);
    }

    @Benchmark
    public boolean isInstanceMethodExplicit() {
        return String.class.isInstance(msg);
    }

    @Benchmark
    public boolean isInstanceRegular() {
        return msg instanceof String;
    }

    @Benchmark
    public String castMethod() {
        return type.cast(msg);
    }

    @Benchmark
    public String castMethodExplicit() {
        return String.class.cast(msg);
    }

    @Benchmark
    public String castRegular() {
        return (String) msg;
    }

}
Run Code Online (Sandbox Code Playgroud)

结果:

Benchmark                          Mode  Cnt       Score       Error  Units
Casting.castMethod                thrpt   20  254604.793 ±  3863.859  ops/s
Casting.castMethodExplicit        thrpt   20  336046.787 ± 10059.986  ops/s
Casting.castRegular               thrpt   20  344369.229 ±  4855.492  ops/s
Casting.isInstanceMethod          thrpt   20  325867.697 ±  6511.731  ops/s
Casting.isInstanceMethodExplicit  thrpt   20  415387.363 ±  2993.788  ops/s
Casting.isInstanceRegular         thrpt   20  396613.371 ± 16799.378  ops/s
Run Code Online (Sandbox Code Playgroud)

ENV:

# JMH version: 1.19
# VM version: JDK 9, VM 9+181
# VM invoker: /usr/lib/jvm/java-9-oracle/bin/java
Run Code Online (Sandbox Code Playgroud)

结果似乎有点出乎意料.双方Class.castClass.isInstance通过类变量调用它们时速度较慢.我的理解是内在应该使这种方法与替代方法一样快.变量会破坏内在优化吗?或者这个开销是预期的?

apa*_*gin 6

方法是内在函数的事实与它们对变量而不是常量一起工作的事实之间没有矛盾.

考虑表达式Math.min(a, 2)Math.min(a, b).方法Math.min在两种情况下都是固有的.但是,第一个表达式显然更快,因为不需要加载变量b,编译器可以直接在cmp指令中内联常量2 .

这同样适用于isInstance/cast方法.当type不是常量时,JVM仍然需要加载变量,检查它是否为非空,然后从java.lang.Class实例加载VM Klass指针.

您可以通过显式禁用内部函数来验证内部函数是否有效.在这种情况下,基准将是很多慢.

@Benchmark
public String castMethod() {
    return type.cast(msg);
}

@Benchmark
@Fork(jvmArgs = {
        "-XX:+UnlockDiagnosticVMOptions",
        "-XX:DisableIntrinsic=_Class_cast,_isInstance",
})
public String castMethodNoIntrinsic() {
    return type.cast(msg);
}
Run Code Online (Sandbox Code Playgroud)

结果:

Benchmark                      Mode  Cnt   Score   Error  Units
Casting.castMethod             avgt   10   4,777 ± 0,065  ns/op
Casting.castMethodNoIntrinsic  avgt   10  28,557 ± 0,124  ns/op
Run Code Online (Sandbox Code Playgroud)