我开发了一个小库,它支持使用注释进行声明性参数验证,如下所示:
@Validate({"not null | number"})
public static Integer notNullAnnotated(Integer number) {
return number++;
}
现在我对纯java代码版本进行基准测试:
public static Integer notNullInline(Integer number) {
if (number != null) {
return number++;
} else {
throw new IllegalArgumentException("argument should not be null");
}
}
,下面是测试:
@Test
public void performanceTest() {
long time = System.nanoTime();
for (int i = 0; i < iterationCount; i++) {
notNullAnnotated(i);
}
System.out.println("time annotated : " + (System.nanoTime() - time));
time = System.nanoTime();
for (int i = 0; i < iterationCount; i++) {
notNullInline(i); // TODO does compiler do any optimization here?
}
System.out.println("time inline : " + (System.nanoTime() - time));
}
我知道这不是进行基准测试的预期方式。现在我宁愿避免为这个简单的测试添加任何实用程序库(因为即使这样结果也很好),但我想知道编译器是否在这里进行了任何优化?
既然您已经在过早的优化路径上走了这么远,请查看Hotspot的PrintAssembly
和CompileThreshold
标志。第一个选项允许您检查Hotspot生成的程序集。第二个选项允许您设置JIT何时启动的阈值。
当然,及时编译器将优化您的代码(假设有相当高的迭代计数),就像在运行该代码的实际程序中一样。因此,在基准测试中,优化本身是可取的。当然,如果代码的人工特性允许对实际代码不可用的优化,那么您就会遇到问题。在您的情况下,编译器可能会推断notNullInline永远不会抛出,因此没有效果,并选择删除整个循环。
如何在Java中编写正确的微基准测试已经讨论过了?