【问题标题】:Why is there run time overhead on the first time a method is called in Java?为什么在 Java 中第一次调用方法时会有运行时开销?
【发布时间】:2016-12-05 03:54:36
【问题描述】:

我正在测量我的代码的执行时间,并在第一次调用一个方法(从主方法)时发现了一些奇怪的行为。这是我的代码,请看一下

public static void main(String[] args) {
    try (Scanner input = new Scanner(System.in)) {
        int iNum = input.nextInt();
        long lStartTime = System.nanoTime();

        // ***********(First call in main) Calling isPrime *************

        lStartTime = System.nanoTime();
        printResult(isPrime(iNum));
        System.out.println("Time Consumed in first call-: " 
                + (System.nanoTime() - lStartTime));

        // ***********(Second call in main) Calling isPrime *************
        lStartTime = System.nanoTime();
        printResult(isPrime(iNum));
        System.out.println("Time Consumed in second call-: "
                + (System.nanoTime() - lStartTime));
    }
}

private static boolean isPrime(int iNum) {
    boolean bResult = true;

    if (iNum <= 1 || iNum != 2 && iNum % 2 == 0) {
        bResult = false;
    } else {
        double iSqrt = Math.sqrt((double) iNum);
        for (int i = 3; i < iSqrt; i += 2) {
            if (iNum % i == 0) {
                bResult = false;
                break;
            }
        }
    }
    return bResult;
}

private static void printResult(boolean bResult) {
    if (bResult)
        System.out.println("\nIt's prime number.");
    else
        System.out.println("\nIt's not prime number.");
}

输入

5

输出

It's prime number.
Time Consumed in first call-: 484073

It's prime number.
Time Consumed in second call-: 40710

说明

上面我只描述了一个输入和输出的测试用例。但是,第一个方法调用和第二个方法调用之间的执行时间总是存在差异的。

我也以类似的方式尝试了两个以上的方法调用,发现除了一个之外,其他调用之间并没有那么大的差异。除了第一个方法调用 484073ns 之外,其余调用的执行时间在 40710ns 左右(这个执行时间在您的系统上可能不同)。很容易我可以看到在第一个方法调用中存在 484073 - 40710 = 443363ns (大约)的时间开销,但为什么会这样呢?根本原因是什么?

【问题讨论】:

  • 第一次调用通常需要编译字节码(一次性成本)。之后,主动 JIT 使后续调用更快(随着时间的推移)。
  • @ElliottFrisch 这种字节码编译(一次性成本)是否仅用于首次调用任何方法(在多个不同方法中)?假设有两个方法isPrimeisPrime2,这两个方法在main中的调用顺序是isPrimeisPrime2isPrimeisPrime2。那么第一次调用isPrime2是否会发生字节码的编译(一次性成本)?
  • Just-in-time compilation 上的维基百科条目中,由于加载和编译字节码所花费的时间,JIT 会导致应用程序的初始执行出现轻微延迟到明显延迟。 i> 甚至更直接 应用程序代码最初被解释,但 JVM 监视哪些字节码序列经常被执行,并将它们转换为机器代码以便在硬件上直接执行。
  • @ElliottFrisch 谢谢,我明白字节码的编译将在第一次调用时发生。请发表您的评论作为答案,以便我可以接受它作为答案。

标签: java performance main execution-time


【解决方案1】:

Java 运行时环境有多种实现,因此并非每个实现都可以像 Oracle(以及以前的 Sun)那样运行。

开始说,在大多数当前的实现中,方法的初始调用涉及验证和 Java 字节码的第一次编译。因此,该方法的后续调用更快。但是,Java 也使用 JIT。维基百科在Just-in-time compilation 上提供了一个条目,其中注释

由于加载和编译字节码所花费的时间,JIT 会导致应用程序初始执行时出现明显延迟。

接着说,

应用程序代码最初被解释,但 JVM 监控哪些字节码序列经常被执行,并将它们转换为机器代码以直接在硬件上执行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-25
    • 2016-12-17
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多