如前所述,JIT(即时)编译器可以优化空循环,以消除不必要的迭代。但是如何?
实际上,有两种JIT编译器:C1和C2。首先,用C1编译代码。C1收集统计信息并帮助JVM发现,在100%的情况下,我们的空循环不会改变任何东西并且是无用的。在这种情况下,C2进入阶段。当代码经常被调用时,可以使用收集的统计信息使用C2对其进行优化和编译。
作为示例,我将测试下一个代码片段(我的JDK设置为slowdebug build 9-internal):
public class Demo {
    private static void run() {
        for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
        }
        System.out.println("Done!");
    }
}
使用以下命令行选项:
-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*Demo.run
而且我的运行方法有不同的版本,并分别使用C1和C2进行编译。对我来说,最终的变体(C2)看起来像这样:
...
; B1: # B3 B2 <- BLOCK HEAD IS JUNK  Freq: 1
0x00000000125461b0: mov   dword ptr [rsp+0ffffffffffff7000h], eax
0x00000000125461b7: push  rbp
0x00000000125461b8: sub   rsp, 40h
0x00000000125461bc: mov   ebp, dword ptr [rdx]
0x00000000125461be: mov   rcx, rdx
0x00000000125461c1: mov   r10, 57fbc220h
0x00000000125461cb: call  indirect r10    ; *iload_1
0x00000000125461ce: cmp   ebp, 7fffffffh  ; 7fffffff => 2147483647
0x00000000125461d4: jnl   125461dbh       ; jump if not less
; B2: # B3 <- B1  Freq: 0.999999
0x00000000125461d6: mov   ebp, 7fffffffh  ; *if_icmpge
; B3: # N44 <- B1 B2  Freq: 1       
0x00000000125461db: mov   edx, 0ffffff5dh
0x0000000012837d60: nop
0x0000000012837d61: nop
0x0000000012837d62: nop
0x0000000012837d63: call  0ae86fa0h
...
有点混乱,但是如果仔细观察,您可能会发现这里没有长时间运行的循环。共有3个块:B1,B2和B3,执行步骤可以为B1 -> B2 -> B3或B1 -> B3。其中Freq: 1-标准化的块执行估计频率。
               
              
javap -v以查看。