Intel'de tartışmasız bir uçucu okuma oldukça ucuzdur. Aşağıdaki basit durumu ele alırsak:
public static long l;
public static void run() {
if (l == -1)
System.exit(-1);
if (l == -2)
System.exit(-1);
}
Java 7'nin montaj kodunu yazdırma yeteneğini kullanarak çalıştırma yöntemi şuna benzer:
# {method} 'run2' '()V' in 'Test2'
# [sp+0x10] (sp of caller)
0xb396ce80: mov %eax,-0x3000(%esp)
0xb396ce87: push %ebp
0xb396ce88: sub $0x8,%esp ;*synchronization entry
; - Test2::run2@-1 (line 33)
0xb396ce8e: mov $0xffffffff,%ecx
0xb396ce93: mov $0xffffffff,%ebx
0xb396ce98: mov $0x6fa2b2f0,%esi ; {oop('Test2')}
0xb396ce9d: mov 0x150(%esi),%ebp
0xb396cea3: mov 0x154(%esi),%edi ;*getstatic l
; - Test2::run@0 (line 33)
0xb396cea9: cmp %ecx,%ebp
0xb396ceab: jne 0xb396ceaf
0xb396cead: cmp %ebx,%edi
0xb396ceaf: je 0xb396cece ;*getstatic l
; - Test2::run@14 (line 37)
0xb396ceb1: mov $0xfffffffe,%ecx
0xb396ceb6: mov $0xffffffff,%ebx
0xb396cebb: cmp %ecx,%ebp
0xb396cebd: jne 0xb396cec1
0xb396cebf: cmp %ebx,%edi
0xb396cec1: je 0xb396ceeb ;*return
; - Test2::run@28 (line 40)
0xb396cec3: add $0x8,%esp
0xb396cec6: pop %ebp
0xb396cec7: test %eax,0xb7732000 ; {poll_return}
;... lines removed
Getstatic için 2 referansa bakarsanız, birincisi bellekten bir yükleme içerir, ikincisi, değer zaten yüklendiği kayıtlardan (kayıtlardan) yeniden kullanıldığında yükü atlar (uzun 64 bit ve 32 bit dizüstü bilgisayarımda 2 kayıt kullanır).
L değişkenini uçucu yaparsak, ortaya çıkan montaj farklı olur.
# {method} 'run2' '()V' in 'Test2'
# [sp+0x10] (sp of caller)
0xb3ab9340: mov %eax,-0x3000(%esp)
0xb3ab9347: push %ebp
0xb3ab9348: sub $0x8,%esp ;*synchronization entry
; - Test2::run2@-1 (line 32)
0xb3ab934e: mov $0xffffffff,%ecx
0xb3ab9353: mov $0xffffffff,%ebx
0xb3ab9358: mov $0x150,%ebp
0xb3ab935d: movsd 0x6fb7b2f0(%ebp),%xmm0 ; {oop('Test2')}
0xb3ab9365: movd %xmm0,%eax
0xb3ab9369: psrlq $0x20,%xmm0
0xb3ab936e: movd %xmm0,%edx ;*getstatic l
; - Test2::run@0 (line 32)
0xb3ab9372: cmp %ecx,%eax
0xb3ab9374: jne 0xb3ab9378
0xb3ab9376: cmp %ebx,%edx
0xb3ab9378: je 0xb3ab93ac
0xb3ab937a: mov $0xfffffffe,%ecx
0xb3ab937f: mov $0xffffffff,%ebx
0xb3ab9384: movsd 0x6fb7b2f0(%ebp),%xmm0 ; {oop('Test2')}
0xb3ab938c: movd %xmm0,%ebp
0xb3ab9390: psrlq $0x20,%xmm0
0xb3ab9395: movd %xmm0,%edi ;*getstatic l
; - Test2::run@14 (line 36)
0xb3ab9399: cmp %ecx,%ebp
0xb3ab939b: jne 0xb3ab939f
0xb3ab939d: cmp %ebx,%edi
0xb3ab939f: je 0xb3ab93ba ;*return
;... lines removed
Bu durumda, l değişkenine yapılan getstatic referanslarının her ikisi de bellekten bir yük içerir, yani değer, çok sayıda uçucu okumada bir kayıtta tutulamaz. Atomik bir okuma olduğundan emin olmak için, değer ana bellekten bir MMX yazmacına movsd 0x6fb7b2f0(%ebp),%xmm0
okunur ve bu da okuma işlemini tek bir talimat yapar (önceki örnekte 64 bit değerinin 32 bitlik bir sistemde normalde iki 32 bit okuma gerektirdiğini gördük).
Dolayısıyla, geçici bir okumanın toplam maliyeti, kabaca bir bellek yüküne eşit olacaktır ve bir L1 önbellek erişimi kadar ucuz olabilir. Bununla birlikte, başka bir çekirdek geçici değişkene yazıyorsa, önbellek satırı, bir ana bellek veya belki de bir L3 önbellek erişimi gerektirecek şekilde geçersiz kılınacaktır. Gerçek maliyet, büyük ölçüde CPU mimarisine bağlı olacaktır. Intel ve AMD arasında bile önbellek tutarlılık protokolleri farklıdır.