ดังที่ได้กล่าวไปแล้วคอมไพเลอร์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
...
มันค่อนข้างยุ่งเล็กน้อย แต่ถ้าคุณมองใกล้ ๆ คุณอาจสังเกตเห็นว่าที่นี่ไม่มีห่วงวิ่งยาว มี 3 บล็อกคือ B1, B2 และ B3 และขั้นตอนการดำเนินการสามารถหรือB1 -> B2 -> B3
B1 -> B3
ที่ไหนFreq: 1
- ความถี่ปกติโดยประมาณของการดำเนินการบล็อก
javap -v
เพื่อดู