Java - 重复的函数调用减少了执行时间

Siv*_*iva 7 performance jvm java-8 java-stream

我有以下代码

public class BenchMark {
    public static void main(String args[]) {
        doLinear();

        doLinear();

        doLinear();

        doLinear();

    }


    private static void doParallel() {
        IntStream range = IntStream.range(1, 6).parallel();

        long startTime = System.nanoTime();
        int reduce = range
                .reduce((a, item) -> a * item).getAsInt();
        long endTime = System.nanoTime();
        System.out.println("parallel: " +reduce + " -- Time: " + (endTime - startTime));
    }

    private static void doLinear() {
        IntStream range = IntStream.range(1, 6);

        long startTime = System.nanoTime();
        int reduce = range
                .reduce((a, item) -> a * item).getAsInt();
        long endTime = System.nanoTime();
        System.out.println("linear: " +reduce + " -- Time: " + (endTime - startTime));
    }

}
Run Code Online (Sandbox Code Playgroud)

我试图对流进行基准测试,但是在一次又一次地调用相同的函数时,执行时间逐渐减少

输出:

linear: 120 -- Time: 57008226
linear: 120 -- Time: 23202
linear: 120 -- Time: 17192
linear: 120 -- Time: 17802

Process finished with exit code 0
Run Code Online (Sandbox Code Playgroud)

第一次和第二次执行时间之间存在巨大差异.

我确信JVM可能会在幕后做一些技巧但是有人能帮我理解那里真的发生了什么吗?

反正有没有避免这种优化,所以我可以测试真正的执行时间?

Mar*_*nik 7

我确信JVM可能会在幕后做一些技巧但是有人能帮我理解那里真的发生了什么吗?

  1. 第一次调用的大量延迟是由于完整的lambda运行时子系统的初始化.您只需为整个申请支付一次.

  2. 您的代码第一次到达任何给定的lambda表达式时,您需要支付该lambda 的链接(invokedynamic调用站点的初始化).

  3. 经过一些迭代后,由于JIT编译器优化了缩减代码,您将看到额外的加速.

反正有没有避免这种优化,所以我可以测试真正的执行时间?

你在这里要求一个矛盾:"真正的"执行时间是热身之后,当所有优化都已应用时你得到的.这是实际应用程序将遇到的运行时.除非您对单次拍摄性能感兴趣,否则前几次运行的延迟与更广泛的图像无关.

为了便于探索,您可以看到代码在禁用JIT编译时的行为:传递-Xintjava命令.还有许多标志禁用了优化的各个方面.