如何进行一次高质量的性能比较测试?

6

要编写一个好的比较测试,必须运行它数千次(甚至数百万次)。这将消除(在大多数情况下)其他程序的影响。

但是如果JVM能够影响结果。例如:

第一个解决方案是:

    final StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append(getStrOne());
    stringBuilder.append(getStrTwo());
    final String result1 = stringBuilder.toString();

第二个内容是:
    final String result2 = getStrOne() + getStrTwo();

我不知道哪个更好,因为JVM可以影响结果。如何知道哪个更好?
更新:我并不是指那个添加比较测试。我是在问这样一个难以测试的情况。

2
JVM对结果有影响是什么意思? - ddmps
1
第二个会被编译器转换为 final String result2 = "str1str2";... - assylias
例如缓存。 - Pavel
1
https://dev59.com/hHRB5IYBdhLWcg3wz6UK - assylias
第二种方法显然更好,因为它更易读,并且固定字符串的连接已经被优化了(即使没有被优化,它也会在内部像使用 StringBuilder 一样处理)。但是,试图在没有 JVM 的影响下测量性能真的没有意义 - 您的程序可能永远不会在没有 JVM 的情况下运行。 - Axel
显示剩余2条评论
2个回答

2
我最近进行了一些基准测试,其中依赖于这篇优秀的IBM文章:http://www.ibm.com/developerworks/java/library/j-benchmark1/index.html
该文章描述了许多可能影响结果准确性的陷阱,例如:
  • 运行时代码优化/重新编译。
  • 死代码消除(即未使用的结果会导致测试代码被删除)
  • 垃圾回收
  • 缓存
  • ...
最后,该文章链接到一个网站,可以下载一个框架。该框架非常好地启动了一个测试方法,寻找重新编译的证据并等待执行时间稳定下来。

0

如果只有两个字符串,性能差异可以忽略不计,但可以尝试以下方法:

String s = "";
for( int i = 0; i < 10000; i++ ) {
  s += i;
}

对比。

StringBuilder b = new StringBuilder();
for( int i = 0; i < 10000; i++ ) {
  b.append(i);
}

你会发现第二个循环要快得多。为什么?因为字符串连接将在每次迭代中创建一个新的String对象,这浪费了CPU周期和内存。

我引用你的话:

要编写一个好的比较测试,你必须测试它数千(百万)次。这将平衡其他程序的影响(在大多数情况下)。

同样适用于单个VM内的测试:多次测试您的代码,使用更大的数据、更大的循环等。仅比较小部分由于时间精度误差和其他影响(例如垃圾收集在其中运行)是没有意义的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接