【发布时间】:2015-07-09 10:02:47
【问题描述】:
最近,我正在使用 Java 编写一个插件,发现第一次从 HashMap 检索元素(使用 get())非常慢。最初,我想问一个问题并找到this(虽然没有答案)。然而,通过进一步的实验,我注意到这种现象发生在ArrayList 上,然后是所有方法。
代码如下:
public class Test {
public static void main(String[] args) {
long startTime, stopTime;
// Method 1
System.out.println("Test 1:");
for (int i = 0; i < 20; ++i) {
startTime = System.nanoTime();
testMethod1();
stopTime = System.nanoTime();
System.out.println((stopTime - startTime) + "ns");
}
// Method 2
System.out.println("Test 2:");
for (int i = 0; i < 20; ++i) {
startTime = System.nanoTime();
testMethod2();
stopTime = System.nanoTime();
System.out.println((stopTime - startTime) + "ns");
}
}
public static void testMethod1() {
// Do nothing
}
public static void testMethod2() {
// Do nothing
}
}
片段:Test Snippet
输出会是这样的:
Test 1:
2485ns
505ns
453ns
603ns
362ns
414ns
424ns
488ns
325ns
426ns
618ns
794ns
389ns
686ns
464ns
375ns
354ns
442ns
404ns
450ns
Test 2:
3248ns
700ns
538ns
531ns
351ns
444ns
321ns
424ns
523ns
488ns
487ns
491ns
551ns
497ns
480ns
465ns
477ns
453ns
727ns
504ns
我运行了几次代码,结果大致相同。在我的计算机(Windows 8.1、Oracle Java 8u25)上,第一次调用会更长(>8000 ns)。
显然,第一次调用通常比后面的调用慢(某些调用在随机情况下可能会更长)。
更新:
我尝试学习了一些JMH,并编写了一个测试程序
带有示例输出的代码:Code
我不知道它是否是一个合适的基准(如果程序有问题,请告诉我),但我发现第一次热身迭代花费更多时间(我使用两次热身迭代以防-ups 影响结果)。而且我认为第一次热身应该是第一次调用并且速度较慢。所以这个现象是存在的,如果测试得当的话。
那为什么会这样呢?
【问题讨论】:
-
JIT编译你了解多少?
-
至于问题的
System.gc()部分,System.gc()不等待GC运行,它在设置了GC应该在最近的机会运行的标志后立即返回,这恰好在您的方法运行时。当然,收集的东西很少,在多核系统上,GC 可以与您的代码并行运行,但是在每个 GC 算法中都有停止世界的步骤。额外的延迟很可能来自于此。 -
实用吗[...] - 问问自己:如果只调用一次,多花几纳秒重要吗?
-
抱歉,我对此了解不多。是字节码吗?
-
@the8472 它在我的程序中将延迟夸大到大约 1 秒。
标签: java performance performance-testing