Neden &; while (i < n) " {} " daha önemli ölçüde daha yavaş "while ( i < n) {}"
Görünüşe göre benim Windows Fi ile 8 laptop 1.7.0_45 (varsayılan tüm derleyici/VM seçenekleri ayarlayın, aşağıdaki döngü ile İLGİLENİYORUZ
final int n = Integer.MAX_VALUE;
int i = 0;
while ( i < n) {
}
büyüklük ise daha hızlı (vs~5000 ms ms ~10) daha en az 2 sipariş
final int n = Integer.MAX_VALUE;
int i = 0;
while (i < n) {
}
Başka bir alakasız performans sorunu değerlendirmek için bir döngü yazarken bu sorunu fark ettim. i < n
i < n
arasındaki fark anlamlı sonucu etkilemek için yeterince büyük.
Eğer koduna bakacak olursak, daha hızlı sürümü döngü cesedini
iinc
iload
ldc
if_icmplt
Ve daha yavaş versiyonu:
iload
iinc
ldc
if_icmplt
i < n
, Bu yüzden ilk 1 tarafından yerel değişken i
kademeli ve yığın i < n
ters sırada bu 2 adım yok iken işlenen üzerine itin. Ama o eski çok daha hızlı olduğunu açıklamak görünmüyor. Herhangi bir geçici kopyasının ikinci durumda yer var mı? Ya da Java (VM uygulama, donanım, vb.) ötesinde bir şey. bu performans farkı için sorumlu olmalıdır?
Okudum başka bir tartışma konusunda i
i
(tamamen değil ama), ama bulamadınız cevap Java-özel doğrudan ilgili durumda i
i
dahil değeri karşılaştırma.
CEVAP
Diğerleri belirttiği gibi, bu test birçok yönden kusurludur.
Bize tam olarak söylemedinnasılbu test yaptın. Ancak, bir "," test (alınmayın) bu gibi: . saf uygulamaya çalıştım
class PrePostIncrement
{
public static void main(String args[])
{
for (int j=0; j<3; j )
{
for (int i=0; i<5; i )
{
long before = System.nanoTime();
runPreIncrement();
long after = System.nanoTime();
System.out.println("pre : " (after-before)/1e6);
}
for (int i=0; i<5; i )
{
long before = System.nanoTime();
runPostIncrement();
long after = System.nanoTime();
System.out.println("post : " (after-before)/1e6);
}
}
}
private static void runPreIncrement()
{
final int n = Integer.MAX_VALUE;
int i = 0;
while ( i < n) {}
}
private static void runPostIncrement()
{
final int n = Integer.MAX_VALUE;
int i = 0;
while (i < n) {}
}
}
Varsayılan ayarlar ile çalışırken, küçük bir fark var gibi görünüyor. Amagerçekkriter kusur -server
bayrağı ile bu çalışma ne zaman belli olur. Benim durumumda sonuçları o zaman boyunca bir şey gibi
...
pre : 6.96E-4
pre : 6.96E-4
pre : 0.001044
pre : 3.48E-4
pre : 3.48E-4
post : 1279.734543
post : 1295.989086
post : 1284.654267
post : 1282.349093
post : 1275.204583
Belli ki, artırma öncesi sürüm olmuşturtamamen uzak optimize edilmiş. Nedeni oldukça basit: neden kullanılmaz. Döngü yürütülür olsun ya da olmasın hiç önemli değil, JİT sadece kaldırır.
Bu etkin çözümü bir göz tarafından onaylandıktan: önceden arttırma sürümü bu kod: sonuç
[Entry Point]
[Verified Entry Point]
[Constants]
# {method} {0x0000000055060500} 'runPreIncrement' '()V' in 'PrePostIncrement'
# [sp 0x20] (sp of caller)
0x000000000286fd80: sub $0x18,%rsp
0x000000000286fd87: mov %rbp,0x10(%rsp) ;*synchronization entry
; - PrePostIncrement::runPreIncrement@-1 (line 28)
0x000000000286fd8c: add $0x10,%rsp
0x000000000286fd90: pop %rbp
0x000000000286fd91: test �x,-0x243fd97(%rip) # 0x0000000000430000
; {poll_return}
0x000000000286fd97: retq
0x000000000286fd98: hlt
0x000000000286fd99: hlt
0x000000000286fd9a: hlt
0x000000000286fd9b: hlt
0x000000000286fd9c: hlt
0x000000000286fd9d: hlt
0x000000000286fd9e: hlt
0x000000000286fd9f: hlt
Olayı sürümünü bu kodun:
[Entry Point]
[Verified Entry Point]
[Constants]
# {method} {0x00000000550605b8} 'runPostIncrement' '()V' in 'PrePostIncrement'
# [sp 0x20] (sp of caller)
0x000000000286d0c0: sub $0x18,%rsp
0x000000000286d0c7: mov %rbp,0x10(%rsp) ;*synchronization entry
; - PrePostIncrement::runPostIncrement@-1 (line 35)
0x000000000286d0cc: mov $0x1,%r11d
0x000000000286d0d2: jmp 0x000000000286d0e3
0x000000000286d0d4: nopl 0x0(%rax,%rax,1)
0x000000000286d0dc: data32 data32 xchg %ax,%ax
0x000000000286d0e0: inc %r11d ; OopMap{off=35}
;*goto
; - PrePostIncrement::runPostIncrement@11 (line 36)
0x000000000286d0e3: test �x,-0x243d0e9(%rip) # 0x0000000000430000
;*goto
; - PrePostIncrement::runPostIncrement@11 (line 36)
; {poll}
0x000000000286d0e9: cmp $0x7fffffff,%r11d
0x000000000286d0f0: jl 0x000000000286d0e0 ;*if_icmpge
; - PrePostIncrement::runPostIncrement@8 (line 36)
0x000000000286d0f2: add $0x10,%rsp
0x000000000286d0f6: pop %rbp
0x000000000286d0f7: test �x,-0x243d0fd(%rip) # 0x0000000000430000
; {poll_return}
0x000000000286d0fd: retq
0x000000000286d0fe: hlt
0x000000000286d0ff: hlt
Bu görünüşte neden tamamen benim için net değildeğilsonrası arttırma sürümü kaldırın. (Aslında, ben ayrı bir soru olarak soran düşünün). Ama en azından, bu farklılıkları ile görebilirsiniz açıklıyor "büyüklük sırası"...
EDİT: Integer.MAX_VALUE-1
Integer.MAX_VALUE
döngü üst sınırı değişiyor olmasıdırher ikisi desürümleri uzak optimize edilmiş ve "zaman. sıfır gerektirir Bir şekilde bu sınırı hala mecliste 0x7fffffff
olarak görüntülenir) optimizasyonu engeller. Muhtemelen, bu karşılaştırma ile ilgili bir şey bir eşlenmiş (yanmış!) cmp
talimat, ama onun ötesinde derin bir sebep veremem. Bu JİT gizemli yollarla çalışır...
Neden sıralanmamış bir dizi daha hızlı...
Neden bu iki kez (1927) garip bir sonu...
Neden HTML düşün” renk? “chucknorris m...
Neden Google while(1); JSON yanıtların...
Neden char[] şifreler için Dize Java t...