2011-09-01 80 views
6

我想测试Java中自动装箱和拆箱的速度,但是当我尝试将其与原始空循环进行比较时,我注意到一件奇怪的事情。这个片断:Java:空循环使用多长时间?

for (int j = 0; j < 10; j++) { 
    long t = System.currentTimeMillis(); 
    for (int i = 0; i < 10000000; i++) 
     ; 
    t = System.currentTimeMillis() - t; 
    System.out.print(t + " "); 
} 

我每次运行它,它返回相同的结果:

6 7 0 0 0 0 0 0 0 0

为什么前两个循环总是需要一定的时间,那么剩下的似乎只是跳过由系统?

In this answer to this post,据说Just-In-Time编译将能够优化这一点。但如果是这样,为什么前两个循环仍需要一些时间?

+3

我认为'System.nanoTime()'更是为这个测试表明(客户端/服务器的虚拟机也应该做一些差异) –

+0

是啊,没错,毫秒往往过于粗粒度。 –

回答

20

JIT触发器多次执行某段代码后。

HotSpot JVM将尝试识别代码中的“热点”。热点是您执行很多次代码的部分。为此,JVM将“计数”各种指令的执行情况,当它确定某个片段频繁执行时,它将触发JIT。 (这是一个近似值,但这很容易理解)。 JIT(Just-In-Time)接受这段代码,并试图使其更快。

使用的JIT,使你的代码运行速度更快的技术有很多,但最常见的造成混乱的一个是:

  1. 它将尝试以确定是否那块代码使用的变量没有用在其他地方(无用的变量),并删除它们。
  2. 如果您获取和同一锁多次释放(如调用同一个对象的synchronized方法),它可以一次性获得锁定,如果你访问对象的成员做一个synchronized块
  3. 所有来电那些没有被声明为volatile的,它可以决定优化它(在寄存器和类似的地方放置值),在多线程代码中创建奇怪的结果。
  4. 它会内联方法,以避免通话费用。
  5. 它会将字节码转换为机器码。
  6. 如果循环完全无用,它可能会被完全删除。

所以,你的问题的正确答案是,被JITed后的空循环,没有时间执行..最有可能不存在了。

同样,还有很多其他的优化,但根据我的经验,这些是最令人头痛的问题。此外,JIT在任何新版本的Java中都得到了改进,有时它甚至会根据平台而有所不同(因为它在某种程度上是平台特定的)。由JIT完成的优化难以理解,因为即使在最近的Java版本中,这些优化中的某些优化已直接移至编译器中,您通常无法使用javap查找它们并检查字节码(例如,自从Java 6编译器能够检测和警告未使用的局部变量和私有方法)。

如果您正在编写一些循环来测试某些内容,通常是将循环放入方法中,在计时之前调用该方法几次以使其“加速”,然后执行定时循环。

这通常会触发在你们这样一个简单的程序的JIT,即使不能保证它确实会触发(或者说,它甚至存在于一定的平台)。

如果你想得到关于JIT或非JIT时间的偏执(我做过):做第一轮,计算每个执行循环的时间,并等待时间稳定(例如,与平均值的差值小于10 %),然后从“真实”时间开始。

7

的JIT不踢上一段代码,直到确定有一些好处这样做。这意味着通过一些代码的前几次通过不会被打乱。

+0

谢谢!我明白了,但空循环可能做什么?或者,正如@Simone詹尼说,JIT(是保证),除非环路已经有一段时间了执行不会被触发?编辑:再次感谢!我从Simone的回答中得到了答案:) –