当通过 class 变量调用时,Java 9 中的 Class.cast 和 Class.isInstance 方法实际上是固有的吗?
Are Class.cast and Class.isInstance methods in Java 9 actually intrinsic when invoking via class variable?
我正在查看 Java 9 中的新内在方法,发现现在方法 Class.cast
is intrinsic 也与 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;
}
}
结果:
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
环境:
# JMH version: 1.19
# VM version: JDK 9, VM 9+181
# VM invoker: /usr/lib/jvm/java-9-oracle/bin/java
结果好像有点出乎意料。 Class.cast
和 Class.isInstance
在通过 class 变量调用它们时都比较慢。我的理解是内在应该使这两种方法与替代方法一样快。
变量会破坏内在优化吗?或者这种开销是预期的?
方法是内在函数与它们对变量而不是常量的工作速度较慢这一事实之间并不矛盾。
考虑表达式 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);
}
结果:
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
我正在查看 Java 9 中的新内在方法,发现现在方法 Class.cast
is intrinsic 也与 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;
}
}
结果:
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
环境:
# JMH version: 1.19
# VM version: JDK 9, VM 9+181
# VM invoker: /usr/lib/jvm/java-9-oracle/bin/java
结果好像有点出乎意料。 Class.cast
和 Class.isInstance
在通过 class 变量调用它们时都比较慢。我的理解是内在应该使这两种方法与替代方法一样快。
变量会破坏内在优化吗?或者这种开销是预期的?
方法是内在函数与它们对变量而不是常量的工作速度较慢这一事实之间并不矛盾。
考虑表达式 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);
}
结果:
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