int与long的迭代速度

时间:2010-04-09 08:19:57

标签: java performance optimization jit

我有以下两个程序:

long startTime = System.currentTimeMillis();
for (int i = 0; i < N; i++);
long endTime = System.currentTimeMillis();
System.out.println("Elapsed time: " + (endTime - startTime) + " msecs");

long startTime = System.currentTimeMillis();
for (long i = 0; i < N; i++);
long endTime = System.currentTimeMillis();
System.out.println("Elapsed time: " + (endTime - startTime) + " msecs");

注意:唯一的区别是循环变量的类型(intlong)。

当我运行它时,无论N的值如何,第一个程序始终打印0到16毫秒。第二个需要更长的时间。对于N == Integer.MAX_VALUE,它在我的机器上运行大约1800毫秒。运行时间在N中似乎或多或少是线性的。

那为什么会这样?

我认为JIT编译器将int循环优化为死亡。并且有充分的理由,因为显然它什么都不做。但是为什么不对long循环也这样做呢?

一位同事认为我们可能正在测量JIT编译器在long循环中的工作,但由于N中的运行时似乎是线性的,所以情况可能并非如此。 / p>

我正在使用JDK 1.6.0更新17:

C:\>java -version
java version "1.6.0_17"
Java(TM) SE Runtime Environment (build 1.6.0_17-b04)
Java HotSpot(TM) 64-Bit Server VM (build 14.3-b01, mixed mode)

我使用的是Windows XP Professional x64 Edition,Service Pack 2,配备2.40GHz的Intel Core2 Quad CPU。


声明

我知道微基准测试在生产中没用。我也知道System.currentTimeMillis()并不像它的名字那样准确。这只是我在鬼混时注意到的事情,我只是好奇为什么会发生这种情况;仅此而已。

4 个答案:

答案 0 :(得分:5)

这是一个有趣的问题,但说实话,我不相信考虑Hotspot在这里的行为会产生有用的信息。你得到的任何答案都不会在一般情况下转移(因为我们正在研究Hotspot在某种特定情况下执行的优化),所以它们会帮助你理解为什么一个no-op比另一个更快, 但它们无法帮助您编写更快的“真实”程序

在这类事情上撰写非常容易误导的微观基准也非常容易 - 请参阅this IBM DW article了解一些常见的陷阱,如何避免它们以及对你正在做的事情的一些一般性评论。

所以这真的是一个“无评论”的答案,但我认为这是唯一有效的答案。编译时平凡的无操作循环 不需要快,因此编译器在某些条件下不会被优化为快速。

答案 1 :(得分:4)

您可能正在使用32位JVM。结果可能与64位JVM不同。在32位JVM中,int可以映射到本机32位整数,并通过单个操作递增。同样不能持续很长时间,这将需要更多的操作来增加。

有关int和long size的讨论,请参阅此question

答案 2 :(得分:3)

我的猜测 - 这只是猜测 - 是这样的:

JVM得出结论,第一个循环实际上什么都不做,所以它完全删除它。没有变量从for循环“逃脱”。

在第二种情况下,循环也没有做任何事情。但可能是确定循环不执行任何操作的JVM代码具有“if(type of i)== int”子句。在这种情况下,删除do-nothing for-loop的优化仅适用于int。

删除代码的优化必须确保没有副作用。 JVM程序员似乎在谨慎方面犯了错误。

答案 3 :(得分:1)

像这样的微基准测试没有多大意义,因为结果很大程度上取决于Hotspot JIT的内部工作原理。

另请注意,使用System.currentTimeMillis()获得的系统时钟值在所有操作系统上的分辨率均不为1 ms。你无法使用它来非常准确地计算持续时间非常短的事件。

看一下这篇文章,解释为什么用Java编写微基准测试并不像大多数人想象的那么简单:Anatomy of a flawed microbenchmark