SORU
21 EYLÜL 2015, PAZARTESİ


Neden Diziler.dolgu HashMap kullanılmaz.artık anlaşıldı mı?

HashMap.clear() uygulama ben bakarak garip bir şey fark ettim. Bu OpenJDK 7u40 görünüyordu

public void clear() {
    modCount  ;
    Arrays.fill(table, null);
    size = 0;
}

Ve bu 60* *şu şekilde görünecektir:

public void clear() {
    Node<K,V>[] tab;
    modCount  ;
    if ((tab = table) != null && size > 0) {
        size = 0;
        for (int i = 0; i < tab.length;   i)
            tab[i] = null;
    }
}

Şimdi table boş harita için boş olabilir, anlıyorum, böylece yerel değişken ek kontrol ve önbelleğe alma gereklidir. Ama neden 9* *için döngü ile değiştirildi mi?

Görünüyor değiştirmek this commit kullanılmaya başlandı. Ne yazık ki döngü için düz Arrays.fill daha iyi olabilir neden hiçbir açıklama buldum. Daha hızlı mı? Ya da daha güvenli?

CEVAP
24 EYLÜL 2015, PERŞEMBE


Yorum önerdikleri üç moreless makul sürümleri özetlemeye çalışacağım.

@says Holger:

Bu sınıf java önlemek için olduğunu tahmin ediyorum.açıklama.Diziler bu yöntemin yan etkisi olarak yükleniyor. Uygulama kodu için, bu genellikle bir sorun değildir.

Bunu test etmek için en kolay şey. Hadi böyle bir program derleme:

public class HashMapTest {
    public static void main(String[] args) {
        new java.util.HashMap();
    }
}

java -verbose:class HashMapTest ile çalıştırın. Bu gerçekleşmediği gibi, sınıf yükleme olayları yazdırır. GÖRDÜM 1.8.0_60 400 ' den fazla ders yüklü görüyorum

... 155 lines skipped ...
[Loaded java.util.Set from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.util.AbstractSet from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.util.Collections$EmptySet from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.util.Collections$EmptyList from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.util.Collections$EmptyMap from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.util.Collections$UnmodifiableCollection from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.util.Collections$UnmodifiableList from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.util.Collections$UnmodifiableRandomAccessList from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded sun.reflect.Reflection from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
**[Loaded java.util.HashMap from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.util.HashMap$Node from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.lang.Class$3 from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.lang.Class$ReflectionData from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.lang.Class$Atomic from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded sun.reflect.generics.repository.AbstractRepository from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded sun.reflect.generics.repository.GenericDeclRepository from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded sun.reflect.generics.repository.ClassRepository from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.lang.Class$AnnotationData from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded sun.reflect.annotation.AnnotationType from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.util.WeakHashMap from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.lang.ClassValue$ClassValueMap from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.lang.reflect.Modifier from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded sun.reflect.LangReflectAccess from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
[Loaded java.lang.reflect.ReflectAccess from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
**[Loaded java.util.Arrays from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
...

Görebilirsiniz, HashMap uzun uygulama kodu önce yüklenir ve Arrays 14 sınıfları HashMap sonra yüklenir. HashMap yük HashMap statik alanları vardır sun.reflect.Reflection başlatma tarafından tetiklenir. Arrays yük aslında clear() yöntemi Arrays.fill 21 ** yük tarafından tetiklenen olabilir. WeakHashMap yük WeakHashMap uzanır java.lang.ClassValue$ClassValueMap tarafından tetiklenir. ClassValueMap java.lang.Class her örneği var. Arrays sınıf olmadan İLGİLENİYORUZ edemiyor hiç başlatılmasını bana öyle görünüyor. Ayrıca Arrays statik başlatıcı çok kısa, sadece onaylama mekanizmasını başlatır. Bu mekanizma, birçok diğer sınıfları da dahil olmak üzere, çok erken yüklenen örnek, java.lang.Throwable) kullanılır. Başka bir statik başlatma adımları java.util.Arrays yapılmaktadır. Böylece @Holger sürüm bana yanlış görünüyor.

Burada da çok ilginç bir şey buldum. WeakHashMap.clear() hala Arrays.fill kullanır. Orada ne zaman ortaya ilginç, ama ne yazık ki bu prehistoric times (zaten orada ilk kamu OpenJDK depo) için de geçerli.

, @MarcoTopolnik says Sonraki:

Kesinlikle güvenli değil amaolabilirfill çağrı inlined değil ve tab kısa olduğunda daha hızlı olacak. Sıcak nokta üzerinde döngü ve fill açık ara hem de hızlı bir derleyici iç (mutlu gün bir senaryoda) neden olur.

Arrays.fill doğrudan intrinsified (intrinsic list @apangin tarafından oluşturulan) değil aslında benim için şaşırtıcı oldu. Gibi böyle döngü ve açık bir iç işleme olmadan JVM tarafından tanınan vectorized olabilir. Ekstra aramak çok özel durumlarda örneğin, eğer MaxInlineLevel sınırına ulaşıldığında () inlined olabilir doğrudur. Öte yandan çok nadir bir durum ve sadece tek bir çağrı, bir çağrı içinde döngü ve bir statik değil, sanal/çağrı arabirimi, böylece performans artışı olabilir sadece marjinal ve sadece bazı özel senaryolar. Olmayan şeyi geliştiriciler genellikle bakım JVM.

Ayrıca unutulmamalıdır hatta C1 'müşteri' derleyici (tier 1-3) yetenekli satır içi Arrays.fill denir, örneğin, WeakHashMap.clear(), satır içi uygulaması günlük (-XX: UnlockDiagnosticVMOptions -XX: PrintCompilation -XX: PrintInlining) diyor ki:

36       3  java.util.WeakHashMap::clear (50 bytes)
     !m        @ 4   java.lang.ref.ReferenceQueue::poll (28 bytes)
                 @ 17   java.lang.ref.ReferenceQueue::reallyPoll (66 bytes)   callee is too large
               @ 28   java.util.Arrays::fill (21 bytes)
     !m        @ 40   java.lang.ref.ReferenceQueue::poll (28 bytes)
                 @ 17   java.lang.ref.ReferenceQueue::reallyPoll (66 bytes)   callee is too large
               @ 1   java.util.AbstractMap::<init> (5 bytes)   inline (hot)
                 @ 1   java.lang.Object::<init> (1 bytes)   inline (hot)
               @ 9   java.lang.ref.ReferenceQueue::<init> (27 bytes)   inline (hot)
                 @ 1   java.lang.Object::<init> (1 bytes)   inline (hot)
                 @ 10   java.lang.ref.ReferenceQueue$Lock::<init> (5 bytes)   unloaded signature classes
               @ 62   java.lang.Float::isNaN (12 bytes)   inline (hot)
               @ 112   java.util.WeakHashMap::newTable (8 bytes)   inline (hot)

Tabii ki, aynı zamanda kolayca akıllı ve güçlü C2 tarafından inlined 'server' derleyici. Bu nedenle burada herhangi bir sorun göremiyorum. @Marco sürümü doğru değil gibi görünüyor.

Son olarak @StuartMarks comments bir çift GÖRDÜM geliştirici, bazı resmi sesi bu yüzden (kim) var:

İlginç. İçimden bir ses bu işte bir yanlışlık var. Bu değişiklik için gözden iplik here ve referanslar continued here earlier thread bir. Daha önce konuya ilk mesaj Doug Lea CVS deposunda hashmap.java bir prototip olduğunu gösteriyor. Bunun nereden geldiğini bilmiyorum. OpenJDK tarihinde hiçbir maç görünmüyor.

... Her durumda, bazı eski anlık görüntü olabilirdi; için döngü açık() yıllardır yöntemi. Diziler.() dolgu çağrı sadece birkaç ay için ağaç oldu this changeset tarafından ortaya atılmıştır. Güç-of-iki hesaplama Tamsayı dayalı olduğunu unutmayın.() highestOneBit this changeset tarafından tanıtılan bu belirtmekle birlikte, inceleme sırasında görevden alındı ama aynı anda ortadan kayboldu. Hmmm.

Gerçekten HashMap.clear() içerdiği döngü yıllar oldu replaced 45* Nisan 10, 2013 ve az kaldı bir yarım yıl kadar Eylül 4 Ne zaman ele commit tanıtıldı. Bu tartışılan aslında JDK-8023463 sorunu düzeltmek için HashMap iç yeniden büyük olduğunu taahhüt eder. Anahtarları hashcodes doğrusal HashMap arama hızı azaltarak, DoS saldırılara karşı savunmasız hale çoğaltarak sahip HashMap zehir için olasılığı hakkında uzun bir hikaye oldu. Bunu çözmek için girişimleri Dize hashCode bazı rasgele dahil olduğunu GÖRDÜM-7 yapıldı. HashMap bu uygulama daha önce, bağımsız olarak geliştirilmiş, daha sonra ana Dalı çeşitli değişiklikler arasında tanıttı üzerine birleşti çatallı taahhüt olduğunu görünüyor.

Bu hipotez bir fark performans destek olabiliriz. Arrays.fill (2013-09-04) kaldırıldı version alıp previous version (2013-07-30) ile karşılaştırın. diff -U0 çıkış 4341 çizgiler vardır. Şimdi Arrays.fill eklendi version bir önceki karşı hadi diff (2013-04-01). Şimdi diff -U0 sadece 2680 satır içerir. Böylece yeni sürümü daha eski için hemen ana benzer aslında.

Sonuç

Stuart Marks ile aynı fikirdeyim sonuçlandırmak için. * *54, aradaki değişim yanlışlıkla üzerine yazıldığı için kaldırmak için somut bir neden yok. Arrays.fill kullanıcı uygulamaları ile İLGİLENİYORUZ kodu hem de gayet iyi ve, örneğin, WeakHashMap kullanılır. Arrays sınıf dolu zaten oldukça erken başlatma sırasında GÖRDÜM, çok basit statik başlatıcı ve Arrays.fill yöntem kolayca inlined bile istemci derleyici, bu yüzden herhangi bir performans dezavantajı unutulmamalıdır.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • backyardjay

    backyardjay

    8 ŞUBAT 2009
  • Caramella Girls

    Caramella Gi

    19 Mayıs 2008
  • Samvith V Rao

    Samvith V Ra

    20 EKİM 2006