减少Java程序相同连续运行的执行时间

时间:2014-04-22 17:31:36

标签: java performance time

背景:我的团队致力于Java程序,该程序接受文本作为输入,处理它并显示结果。程序的每次运行都是无状态的,独立于其他运行。我们注意到,当在同一文本的循环中运行处理方法时,然后始终如一,第一次运行需要最长时间才能完成,而下一次运行所花费的时间越来越少,直到执行时间在几十次运行后稳定一个远低于初始运行时间的值。

我试图测试这是否是任何程序的一般现象,并尝试运行以下代码,该代码具有嵌套循环,并测量内循环所花费的时间:

String s = "abcefghijklmnopqrstuvwxyz";
int TIMES = 10;
int INNER_TIMES = 1000000; 
long count = 0;     
for (int i = 0; i < TIMES; i++) {       
    long start = System.currentTimeMillis();
    for (int j = 0; j < INNER_TIMES; j++) {
        List<String> list = new ArrayList<>();
        list.add(s);
    }
    count++;
    long end = System.currentTimeMillis();          
    double time = (end - start) / 1000.0;
    System.out.println(count + ": " + time + " seconds");
}

结果与我们在程序中注意到的相似:

1: 0.036 seconds
2: 0.018 seconds
3: 0.016 seconds
4: 0.009 seconds
5: 0.01 seconds
6: 0.009 seconds
7: 0.02 seconds
8: 0.014 seconds
9: 0.009 seconds
10: 0.01 seconds

我尝试过多次运行,结果非常一致。内循环的第一次运行总是需要大约0.035-0.036秒,从第4次运行开始(即使将TIMES增加到1000),它需要大约0.008-0.01秒(除了一些例外)。

我和我的团队负责人都为此感到难过。这是Java中的已知现象吗?在软件中一般?为什么看起来软件需要热身&#34;在达到最佳性能之前?

2 个答案:

答案 0 :(得分:2)

这是Java应用程序的正常行为,这也意味着您不应该优化应用程序,除非已经证明使用分析器确定了瓶颈。 JVM将通过在运行时使用JIT(实时)编译来提高代码的性能。

您可以在此处找到有关JIT优化的更多信息:The Java HotSpot Performance Engine Architecture. Chapter 3. The Java HotSpot Compilers


除此之外,你正在为自己的代码做一个非常天真的基准测试。我建议您阅读How do I write a correct micro-benchmark in Java?以增强您的代码评估的当前结果,甚至更好,使用真实的基准框架,如caliperJUnitBenchmarks

答案 1 :(得分:1)

这里可能有多种因素:

  • 第一次执行代码时,JIT编译器可能正在将Java字节码编译为本机代码,例如后续调用可能更快(最有可能解释您看到的行为)
  • 本地代码可能由CPU缓存

我相信你可以关闭JIT(-Djava.compiler=NONE)来验证第一个理论(虽然我之前从未关闭过JIT)