Java 9+ 中是否有更便宜的方法调用来保持其安全点?
JVM 在运行时移除安全点以提高效率,但这会使分析和监控代码变得更加困难。出于这个原因,我们特意在精心挑选的地方添加了琐碎的调用,以确保存在安全点。
public static void safepoint() {
if (IS_JAVA_9_PLUS)
Thread.holdsLock(""); // 100 ns on Java 11
else
Compiler.enable(); // 5 ns on Java 8
}
public static void optionalSafepoint() {
if (SAFEPOINT_ENABLED)
if (IS_JAVA_9_PLUS)
Thread.holdsLock("");
else
Compiler.enable();
}
Run Code Online (Sandbox Code Playgroud)
在 Java 8 上,这种开销很好,但Compiler.enable()在 Java 9+ 中被优化掉了,所以我们必须使用更昂贵的方法,或者不启用此功能。
编辑:除了分析器之外,我还使用了safepoint()从中获取更好的细节,Thread.getStackTrace()以便应用程序可以对其自身进行分析,例如,当执行操作需要很长时间时。
考虑下面两个长度为2的代码片段:
boolean isOK(int i) {
for (int j = 0; j < filters.length; ++j) {
if (!filters[j].isOK(i)) {
return false;
}
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
和
boolean isOK(int i) {
return filters[0].isOK(i) && filters[1].isOK(i);
}
Run Code Online (Sandbox Code Playgroud)
我认为,经过充分的预热后,这两块琴的性能应该相似。
我已经使用JMH微基准测试框架(如此处和此处所述)进行了检查,并观察到第二个片段的运行速度提高了10%以上。
问题:为什么Java没有使用基本循环展开技术优化我的第一个代码段?
特别是,我想了解以下内容:
return (filters.length) == 2 ? new FilterChain2(filters) : new FilterChain1(filters)。JITC可以这样做吗?如果不能,为什么?理想情况下,我想从对JITC的工作有深刻理解的人那里得到答案。
基准运行细节:
我尝试了两种方法在 java.lang.String 上逐个字符地迭代,发现它们令人困惑。该基准对其进行了总结:
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(jvmArgsAppend = {"-Xms2g", "-Xmx2g"})
public class CharByCharIterationBenchmark {
@Benchmark
public void toCharArray(Data data, Blackhole b) {
char[] chars = data.string.toCharArray();
for (char ch : chars) {
b.consume(ch);
}
}
@Benchmark
public void charAt(Data data, Blackhole b) {
String string = data.string;
int length = string.length();
for (int i = 0; i < length; i++) {
b.consume(string.charAt(i));
}
}
@State(Scope.Thread)
public static class Data {
String string;
@Param({"true", "false"})
private boolean latin;
@Param({"5", "10", "50", "100"}) …Run Code Online (Sandbox Code Playgroud)