Java:空循环使用多长时间?

zw3*_*324 7 java performance primitive jit loops

我试图在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 + " ");
}
Run Code Online (Sandbox Code Playgroud)

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

6 7 0 0 0 0 0 0 0 0

为什么前两个循环总是需要一些时间,其余的似乎被系统跳过?

在这篇文章的答案中,据说Just-In-Time编译将能够优化这一点.但如果是这样,为什么前两个循环还需要一些时间?

Sim*_*nni 20

JIT在某段代码执行多次后触发.

HotSpot JVM将尝试识别代码中的"热点".热点是您的代码片段,可以执行很多次.为此,JVM将"计算"各种指令的执行,并且当它确定经常执行某个部分时,它将触发JIT.(这是一个近似值,但很容易理解这种方式解释).

JIT(Just-In-Time)接受了这段代码,并试图让它更快.

JIT用于使代码运行更快的技术很多,但最常引起混淆的是:

  1. 它将尝试确定该段代码是否使用其他地方未使用的变量(无用变量),并将其删除.
  2. 如果多次获取并释放相同的锁(比如调用同一对象的同步方法),它可以获取一次锁并在单个同步块中执行所有调用
  3. 如果访问未声明为volatile的对象的成员,则可以决定对其进行优化(将值放在寄存器中等等),从而在多线程代码中创建奇怪的结果.
  4. 它将内联方法,以避免调用的成本.
  5. 它会将字节码转换为机器码.
  6. 如果循环完全无用,可以完全删除.

所以,你的问题的正确答案是,在JIT之后,一个空循环没有时间执行..很可能不再存在了.

同样,还有许多其他的优化,但根据我的经验,这些是最令人头疼的问题.

此外,JIT正在改进任何新版本的Java,有时甚至根据平台有所不同(因为它在某种程度上是特定于平台的).JIT完成的优化很难理解,因为你通常不能使用javap和检查字节码找到它们,即使在最新版本的Java中,其中一些优化已经直接转移到编译器(例如,因为Java 6编译器是能够检测并警告未使用的局部变量和私有方法).

如果你正在编写一些循环来测试某些东西,通常最好将循环放在一个方法中,在计时之前调用该方法几次,给它一个"加速"循环,然后执行定时循环.

这通常会在像你这样的简单程序中触发JIT,即使不能保证它实际上会触发(或者它甚至存在于某个平台上).

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


Han*_*Gay 8

在确定这样做有一些好处之前,JIT不会对一大块代码起作用.这意味着通过一些代码的前几次传递将不会被JIT.