如何禁用编译器和JVM优化?

我有这个代码正在测试与:Calendar.getInstance().getTimeInMillis()System.currentTimeMilli()

long before = getTimeInMilli();
for (int i = 0; i < TIMES_TO_ITERATE; i++)
{
  long before1 = getTimeInMilli();
  doSomeReallyHardWork();
  long after1 = getTimeInMilli();
}
long after = getTimeInMilli();
System.out.println(getClass().getSimpleName() + " total is " + (after - before));

我想确保没有发生JVM或编译器优化,所以测试将是有效的,并且实际上将显示差异。

如何确定?

编辑:我更改了代码示例,因此它将更加清晰。我在这里检查的是调用不同实现所需的时间 - vs .getTimeInMilli()CalendarSystem


答案 1

我认为您需要禁用JIT。添加到运行命令下一个选项:

-Djava.compiler=NONE

答案 2

您希望优化发生,因为它在现实生活中会生效 - 如果JVM没有以与您感兴趣的真实情况相同的方式进行优化,则测试将无效。

但是,如果你想确保JVM不会删除它可能认为没有操作的调用,否则,一种选择是使用结果 - 所以如果你重复调用,你可以对所有返回值求和,然后在最后显示总和。System.currentTimeMillis()

请注意,您可能仍然有一些偏差 - 例如,如果 JVM 可以廉价地确定自上次调用 以来只经过了一小部分时间,那么可能会有一些优化,因此它可以使用缓存值。我并不是说这里的情况确实如此,但这是你需要考虑的那种事情。最终,基准测试只能真正测试您给它们的负载。System.currentTimeMillis()

需要考虑的另一件事是:假设你想对代码运行频繁的真实情况进行建模,你应该在进行任何计时之前运行代码很多 - 因为Hotspot JVM将逐步优化,并且可能你关心的是高度优化的版本,并且不想测量JITting的时间和代码的“慢速”版本。

正如斯蒂芬所提到的,你几乎肯定应该把时间放在循环之外......并且不要忘记实际使用结果...


推荐