Java执行时间受字符串格式化影响?

Tom*_*Tom 0 java performance java-8

我正在使用以下简单代码进行一些性能测试(总计大约一百万个整数):

final int[] array = new int[1024 * 1024];

// populate values
for (int i = 0; i < array.length; i++) {
    array[i] = i % 100;
}

long start, end, sum = 0;

start = System.nanoTime();

// calculate sum
for (int i : array) {
    sum += i;
}

end = System.nanoTime() - start;

System.out.println(end);
Run Code Online (Sandbox Code Playgroud)

平均执行时间约为1.8毫秒.

然后我决定改变测试结果的演示.我替换System.out.println(end)为以下语句(格式化字符串):

System.out.printf("Time in %dns, sum: %d\n", end, sum);
Run Code Online (Sandbox Code Playgroud)

当我注意到我的平均执行时间大约是2.8毫秒时,这是非常令人惊讶的.它只有一毫秒(不是什么大不了),但另一方面它慢了约50%.更重要的是,测试结果表示(和格式化)位于结束时间测量之后,因此从理论上讲它不应该影响平均执行时间.

你知道为什么平均执行时间在添加System.out.printf语句后需要更多时间吗?它是由重新排序(在为end变量赋值之前执行的格式化)引起的吗?

Ste*_*n C 5

我认为你不能从中得出任何结论.基本上,您的基准是有缺陷的:

  1. 在捕获测量之前,没有采取必要的步骤来预热 JVM.

  2. 执行您正在测量的"工作"的循环可以进行优化.编译器(javac或JIT编译器)可以推断出sum从未使用过,因此不计算它.

这些缺陷中的任何一个都可能会扭曲您所看到的结果.


对于它的价值,如果基准测试正确,那么花哨的格式化根本不应该对测量的时间有所贡献.

  • 是的,死代码消除在这里工作.绝对不是由`javac`,而是由JIT编译器.如果你正确地进行基准测试,使用和不使用`sum`的差异会大得多.课程:非常小心地测量并使用适当的测量线束,例如`jmh`. (8认同)