为什么第一次 nanoTime() 调用和后续调用之间的时间差异如此之大?

Why is there such a big difference on time between first nanoTime() call and the successive calls?

所以我的问题比较笼统。我有以下简单代码:

for(int i=0;i<10;i++){
    long starttime=System.nanoTime();
    System.out.println("test");
    long runtime=System.nanoTime()-starttime;
    System.out.println(i + ":" +"runtime="+runtime);
}

我收到以下输出:

test
0:runtime=153956
test
1:runtime=15396
test
2:runtime=22860
test
3:runtime=11197
test
4:runtime=11197
test
5:runtime=12129
test
6:runtime=11663
test
7:runtime=11664
test
8:runtime=53185
test
9:runtime=12130

第一次运行时和第二次运行时有区别的原因是什么?提前致谢=)

JVM 花费了一些时间来初始化所有需要的对象、访问系统时间、系统输出流等...您有两种方法介于两者之间:

System.nanoTime() 
System.out.println() 

其中每一个都可以执行大量初始化代码)。

每次连续调用都快得多,因为这一切都已经设置好了。因此,当对应用程序的性能进行基准测试时,通常会丢弃预热和冷却阶段(例如,第一个和最后 15 分钟)。

JVM 和标准库中的很多东西都被延迟初始化以改善 JVM 启动时间。所以第一次执行行

System.out.println("test");

一个重量级的初始化过程发生了。完成它的时间包含在您的第一次测量中。随后的调用沿着状态已经初始化的快速路径进行。

您可以在 Java 中的大量 API 调用中观察到相同的效果。

当然,还有更多因素会影响完成任何给定方法调用所需的时间,尤其是当它在其路径上包含系统调用时。然而,first 调用延迟中的异常值是特殊的,因为它具有潜在的确定性原因,因此可以可靠地重现。

很多事情都会影响您的计算。

你机器上的其他进程怎么样?您是否考虑过 JVM 预热?也许是垃圾收集?所有这些因素以及更多因素导致了这种行为。

如果您想获得 "better" 个结果,您应该 运行 多次,然后取平均值。

这就是为什么您应该知道如何在 Java 中进行基准测试,请参阅 How do I write a correct micro-benchmark in Java?