【问题标题】:Why does the first method call always take the longest?为什么第一个方法调用总是耗时最长?
【发布时间】:2017-02-11 01:16:01
【问题描述】:

在阅读了有关 Stack Overflow 上的类似主题后,我编写了以下代码来了解 System.nanoTime() 的一致性。

它只是在对空的 void 函数进行方法调用之前和之后调用 System.nanoTime(),记录过程中经过的时间。但是,正如您在结果中看到的那样,第一次调用总是花费最长的时间。这是什么原因?

public class Test {
    public static void main(String[] args) {
        for(int i = 0; i < 10; i++) {
            double start = System.nanoTime();
            foo();
            double end = System.nanoTime();
            double diff = end - start;
            System.out.println("Diff: " + diff);
        }
    }

    public static void foo() {

    }
}

结果:

Diff: 2765.0
Diff: 509.0
Diff: 236.0
Diff: 238.0
Diff: 230.0
Diff: 539.0
Diff: 359.0
Diff: 356.0
Diff: 380.0
Diff: 353.0

请注意,我确实读过这个问题:Why does first call to java.io.File.createTempFile(String,String,File) take 5 seconds on Citrix?

此外,此链接有助于将来参考,但不一定回答我的具体问题:How do I write a correct micro-benchmark in Java?

【问题讨论】:

  • 一句话:“缓存”(在各种层上)。一旦涉及到缓存,第二次做同样的事情就会快得多。另外,2 微秒的差异确实没什么好担心的,为什么要将 nanoTime 转换为浮点数?
  • 那个方法真的是空的吗?也许 JVM 会发现并完全优化它?请做两个跟进:a)在没有任何代码或方法调用的情况下测量 nanoTime 差异 b)在 foo 方法中进行一些小计算。
  • JVM 上的微基准测试很难,因为JIT compiler 可以在代码运行一段时间后巧妙地改变代码的工作方式。正确的方法是使用真正的基准测试框架,如 jmh
  • 并非总是如此。我恢复了你的实验,有时它不是第一个需要最长时间的实验。我的jdk1.8和操作系统win10。
  • 运行代码更长例如20_000 次,它将内联该方法,并将减少调用 System.nanoTime() 所需的时间

标签: java time jvm system


【解决方案1】:

JVM 懒惰地执行类解析(参见JVMS 5.4.3)。在您的情况下,常量池中对 foo 的符号引用在第一次执行 invokestatic 字节码时解决,即在第一次调用该方法时。显然,它比仅仅执行一个已经解析的字节码需要更多的时间。

【讨论】:

    猜你喜欢
    • 2020-07-20
    • 1970-01-01
    • 2019-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-21
    相关资源
    最近更新 更多