1

我有这个代码:

public static void main(String[] args) {

    long f = System.nanoTime();

    int a = 10 + 10;

    long s =System.nanoTime();

    System.out.println(s - f);

    long g = System.nanoTime();

    int b = 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10;

    long h =System.nanoTime();

    System.out.println(h - g);

}

使用此输出/秒:
测试 1:

427
300

测试 2:

533
300

测试 3:

431
398

根据我的测试场景,为什么这条线的int b = 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10;执行速度比int a = 10 + 10;?

4

3 回答 3

5

众所周知,微基准测试很难做到正确,尤其是在 Java 等“智能”语言中,编译器和 Hotspot 可以在这些语言中进行大量优化。你几乎肯定没有测试你认为你正在测试的东西。阅读Anatomy of a Flawed Microbenchmark以获取更多细节和示例(现在这是一篇相当老的文章,但原则与以往一样有效)。

在这种特殊情况下,我可以立即看到至少三个问题:

  • 代码根本不会执行任何加法,因为编译器将为变量分配它们的编译时常量值。(即,就好像您的代码读取int a = 20;int b = 120;
  • 的粒度nanoTime在大多数系统上都相当高。这与来自操作系统的负载相结合,意味着您在测量中的实验误差远大于结果本身的幅度。
  • 即使发生了添加,您也没有“预热”虚拟机;通常,由于这个原因,您放在第二位的任何操作都会显得更快。

可能还有更多潜在的危险潜伏着。

The moral of the story is test your code in real-world conditions, to see how it behaves. It is in no way accurate to test small pieces of code in isolation and assume that the overall performance will be the sum of these pieces.

于 2013-06-03T10:10:22.490 回答
4

首先。Java 编译器对常量表达式进行优化,所以你的代码在编译时会被转换为:

int b = 120;

结果 JV​​M几乎同时a=20执行分配。b=120

第二个。您对大系统执行简短测量(我的意思是整个计算机,包括操作系统、交换进程、另一个运行进程......)。因此,您可以在非常短的时间内获得随机系统的快照。这就是为什么你不能推断出a赋值比b. 为了证明这一点,您必须将代码测量放入相当大的循环中 - 重复执行大约 1,000,000 次。如此大的重复可以让你平滑期望(在这个词的数学意义上)

于 2013-06-03T10:07:39.273 回答
2

这不是衡量性能的正确方法。

首先,不要测量这么小的一段代码。相反,像@NilsH 建议的那样调用它数百万次,并通过将经过的时间除以调用次数来获得平均时间。

其次,JVM 可能会对您的代码执行优化,因此您需要给它一个“热身”时间。让几百万“干”运行而不测量时间,而不是开始测量。

于 2013-06-03T10:08:05.737 回答