Java 为什么第一个nanoTime()调用和后续调用在时间上有如此大的差异?

Java 为什么第一个nanoTime()调用和后续调用在时间上有如此大的差异?,java,system,nanotime,Java,System,Nanotime,所以我的问题更一般。我有以下简单的代码: 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); } 第一次运行时和第二次运行时之间存在差异的原因是什么?提前感谢=

所以我的问题更一般。我有以下简单的代码:

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);
}

第一次运行时和第二次运行时之间存在差异的原因是什么?提前感谢=)

JVM花了一些时间初始化所有需要的对象、访问系统时间、系统输出流等。。。在这两种方法之间有两种方法:

System.nanoTime() 
System.out.println() 
每个人都可能执行了大量的初始化代码)


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

JVM和标准库中的许多内容都会延迟初始化,以缩短JVM启动时间。第一次执行该行时

System.out.println("test");
一个重量级的初始化过程发生。完成时间包含在您的第一次测量中。后续调用沿着状态已初始化的快速路径进行

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


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

许多事情都会影响您的计算

您机器上的其他进程如何?你有没有考虑过强JVM预热<强>?可能是垃圾收集?所有这些因素以及更多因素导致了这种行为

如果你想得到“更好”的结果,你应该运行更多次,取平均值


这就是为什么您应该知道如何在Java中对事物进行基准测试,请参阅。

参考此问题,它可能会有所帮助。优化/预测可能会有帮助吗?+静态“测试”初始化JVM首次使用JIT编译器将JVM字节码编译成真实的机器代码。编译的时间包含在第一个间隔中。只有上帝知道为什么第九次调用会慢一点。这不是问题所在。第一个调用之所以慢是因为Java懒散地初始化东西、获取操作系统句柄等…或者运行JIT编译器@PeterPaulKiefer由于我有相反的信息,您能否提供任何可靠的源代码,说明JIT编译器在代码的第一次迭代中使用默认的JVM设置?@PeterPaulKiefer您链接到了一个关于JIT编译器一般用途的问答。我的问题要具体得多:提供参考以支持JIT编译在代码的第一次迭代中发生的断言。另一个众所周知的事实是,为了触发JIT编译,代码必须通过多次执行来“预热”(具体来说,10000次迭代是阈值的默认值)。我真的很惊讶你还没有意识到这个事实。即使使用分层编译,C1也不会在第一次运行时使用。@PeterPaulKiefer
JVM可以很早就做出决定
——在这里,您承认您不知道在这种特殊情况下实际会发生这种情况。考虑到
System.out.println()
调用是一个非常特殊的情况,并且JVM提供了非常具体的支持(从
out
开始,它是一个最终的空值字段,这是一个神奇的、语言外的惰性初始化的明显标志),您的断言实际上没有什么分量。你声称额外的延迟是关于JIT编译来排除所有其他东西的,尤其是毫无根据的。@ MARKOTPOLNIK-我应该考虑这个问题,不仅仅是第一呼叫,还有第九呼叫。那么,我相信这是唯一正确描述所有可能正在发生的事情的答案。我不会只考虑第一种情况。你应该给出所有观察结果的答案。
如果你想得到“更好”的结果,你应该运行更多次,并取平均值。
——你的意思是,多次运行同一个程序?OP确实这样做了,并且注意到,每次第一次通话都需要更长的时间。这个问题与微基准标记有关的唯一一件事是它询问了一个特定的陷阱及其原因。OP接受了它。。所以这似乎是一个答案。这些问题不需要回答,它们是OP的提示,我想他理解了。是的,非常感谢,在我看来有几个正确的答案
System.out.println("test");