이미 지적했듯이 JIT (just-in-time) 컴파일러는 불필요한 반복을 제거하기 위해 빈 루프를 최적화 할 수 있습니다. 하지만 어떻게?
실제로 두 가지 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
...
조금 지저분하지만 자세히 살펴보면 여기에 오래 실행되는 루프가 없다는 것을 알 수 있습니다. B1, B2 및 B3의 3 개 블록이 있으며 실행 단계는 B1 -> B2 -> B3
또는 일 수 있습니다 B1 -> B3
. 어디서 Freq: 1
-블록 실행의 정규화 된 예상 빈도.
javap -v
볼 수 있도록 바이트 코드를 조사 하십시오.