背景:我的团队致力于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;在达到最佳性能之前?
答案 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?以增强您的代码评估的当前结果,甚至更好,使用真实的基准框架,如caliper或JUnitBenchmarks
答案 1 :(得分:1)
这里可能有多种因素:
我相信你可以关闭JIT(-Djava.compiler=NONE
)来验证第一个理论(虽然我之前从未关闭过JIT)