Ne zaman WeakHashMap veya WeakReference kullanırsınız?


163

Zayıf referansların kullanımı, daha önce hiç uygulama görmediğim bir şeydir, bu yüzden onlar için kullanım durumunun ne olduğunu ve uygulamanın nasıl çalışacağını anlamaya çalışıyorum. Bir WeakHashMapveya WeakReferencene zaman kullanmanız gerekti ve nasıl kullanıldı?



Yanıtlar:


96

Güçlü referanslardaki bir sorun, özellikle görüntüler gibi çok büyük yapılarda önbelleklemedir. Üzerinde çalıştığım web sitesi tasarım aracı gibi kullanıcı tarafından sağlanan resimlerle çalışması gereken bir uygulamanız olduğunu varsayalım. Doğal olarak bu görüntüleri önbelleğe almak istersiniz, çünkü bunları diskten yüklemek çok pahalıdır ve aynı anda (potansiyel olarak devasa) görüntünün iki kopyasının aynı anda bellekte bulunma olasılığından kaçınmak istersiniz.

Bir görüntü önbelleğinin, kesinlikle ihtiyacımız olmadığında görüntüleri yeniden yüklememizi önlemesi gerektiğinden, önbelleğin her zaman bellekte olan herhangi bir görüntüye bir referans içermesi gerektiğini hızlı bir şekilde fark edeceksiniz. Bununla birlikte, sıradan güçlü referanslarla, bu referansın kendisi görüntüyü bellekte kalmaya zorlar, bu da bir şekilde görüntünün artık bellekte gerekmediğini belirlemenizi ve önbellekten kaldırmanızı gerektirir, böylece çöp toplama için uygun hale gelir. Çöp toplayıcının davranışını çoğaltmak ve bir nesnenin bellekte olup olmayacağını el ile belirlemek zorundasınız.

Zayıf Referansları Anlama , Ethan Nicholas


43
SoftReferences bu durumda daha iyi olmaz, yani sadece bellek tükendiğinde toplanan referanslar.
JesperE

Biraz kafam karıştı ... Diyelim ki SWT Image önbelleğim var. SWT görüntülerinin SO Resources'ı serbest bırakmak için dispose () yöntemiyle DISPOSED olması gerekir. Bunları saklamak için bir WeakHashMap kullanırsam, GC tam olarak nesneyi atacak mı?
marcolopes

2
@marcolopes GC başka bir nesne üzerinde bir sonlandırıcı kullanır. SWT bunu yaptığınızda hoşlanmıyor gibi görünüyor, bu yüzden işletim sistemi kaynaklarını bir ile yönetebileceğinizi düşünmüyorum WeakHashMap.
Jacob Krall

@marcolopes, (GC'nizin belleği geri kazanmadan önce sonlandırma çağrısını garanti ettiğini varsayacağım.) Önbellek sonlandırıcıda imha işlemi yapılırsa her şey yolunda demektir. Eğer imha, el ile çağırmanız gereken bir şeyse, 1) sınıfı genişletip sonlandırıcıya atın veya 2) imhayı uygun şekilde izlemek ve çalıştırmak için hayali tercih kullanın. Seçenek 2 daha iyidir (diriliş hatalarını önler ve size başka bir iş parçacığında imha etme olanağı verir), ancak seçenek 1 yardımcı sınıf olmadan uygulanması daha kolaydır.
Pacerier


55

WeakReference karşı SoftReference

Açıklığa kavuşturulması gereken bir ayrım, a WeakReferenceve a arasındaki farktır SoftReference.

Temel olarak , atıfta bulunulan nesnenin buna hiçbir sert referansı olmadığında , JVM tarafından hevesle GC-dWeakReference olacaktır . Öte yandan bir d nesnesi, gerçekten belleği geri kazanması gerekene kadar çöp toplayıcı tarafından bırakılma eğilimindedir.SoftReference

DeğerlerinWeakReference s içinde tutulduğu bir önbellek oldukça işe yaramaz olacaktır (a WeakHashMap, zayıf referans verilen anahtarlardır). SoftReferenceskullanılabilir bellekle büyüyebilen ve daralan bir önbellek uygulamak istediğinizde değerleri sarmak için kullanışlıdır.


4
"Değerlerin WeakReferences içinde tutulduğu bir önbellek oldukça işe yaramaz" Kesinlikle katılmıyorum.
Thomas Eding

5
@trinithis - erm, ne diyeceğimi bilmiyorum. Tam olarak faydalı bir şey göndermediğiniz anda değerleri kaybolan bir önbellek neden tam olarak faydalıdır ?
oxbow_lakes

4
Notlama gibi bir şey için, önbelleğe alınmış değerlerini gevşek bir şekilde tutan bir önbellek yararlı olabilir.
Thomas Eding

5
@ThomasEding Hala anlamıyorum. Önbelleğin yararlı göründüğü tek zaman, başka referans olmadığı zaman ... Referansınız varsa, ne için önbelleğe ihtiyacınız var?
Cruncher

2
@ThomasEding, Softref çevreye "hafızanız kalmayıncaya kadar sakla" der. Weakref çevreye "GC çalışana kadar sakla" der. GC'nin hatalarını ayıklama / profil oluşturmadığınız sürece, açık bir şekilde zayıf başvuru için bir kullanım durumu yoktur. Belleğe duyarlı bir önbellek istiyorsanız softref kullanın. Önbellek istemiyorsanız önbelleklemeyin! Poorref nereye giriyor?
Pacerier

30

Özellikle WeakReferences ve WeakHashMaps'nin ortak kullanımı, nesnelere özellik eklemek içindir. Bazen bir nesneye bazı işlevler veya veriler eklemek istersiniz, ancak alt sınıf ve / veya kompozisyon bir seçenek değildir, bu durumda yapılacak en belirgin şey, eklemek istediğiniz nesneyi genişletmek istediğiniz nesneyi bağlayan bir hashmap oluşturmak olacaktır. . o zaman özelliğe ihtiyacınız olduğunda onu haritada bulabilirsiniz. Bununla birlikte, özellikler eklediğiniz nesneler yok edilme ve çok fazla oluşturma eğilimi gösteriyorsa, haritanızda çok fazla bellek alan çok sayıda eski nesne bulunabilir.

Eğer bir kullanırsanız WeakHashMapyerine nesneleri artık istenen davranıştır programınızın, geri kalanı tarafından kullanılmaktadır yakında kadar haritanızı bırakacaktır.

Ben bazı veri eklemek için bunu yapmak zorunda java.awt.Component1.4.2 ve 1.5 arasında JRE bir değişiklik aşmanın, ben ilgi int (oldu her bileşeni sınıflara göre düzelttim olabilirdi JButton, JFrame, JPanel....) ama bu fazlaydı çok daha az kodla daha kolay.


1
WeakHashMap "artık programınızın geri kalanı tarafından kullanılmıyor" kelimesini nasıl biliyor?
Vinoth Kumar CM

2
Zayıf bir hasmap, anahtarları için zayıf referanslar kullanır. Bir nesneye yalnızca zayıf referanslarla başvurulduğunda, çöp toplayıcı zayıf referansın sahibini (bu durumda WeaHashMap) 'bilgilendirir'. Bu nesnelerin çöp toplayıcı ile nasıl etkileşime girdiğini anlamak için Javadocs WeakReferences ve ReferenceQueues okurdum.
Luke

1
teşekkürler luke, obove açıklama için basit bir kod sağlayabilir?
kaynamış su

Bu nedenle, zayıf referans , Java'da, bazı sınıfların genişletilemediği Java'nın ilginç API'si nedeniyle anlamlıdır .
Pacerier

22

İçin bir başka kullanışlı durum WeakHashMapve WeakReferencebir olan dinleyici kayıt uygulaması .

Belirli olayları dinlemek isteyen bir şey oluşturduğunuzda, genellikle bir dinleyici kaydedersiniz, ör.

manager.registerListener(myListenerImpl);

Eğer managermağazalarda bir ile dinleyici WeakReference, bir ile kayıt örneğin kaldırmak gerekmez demekse manager.removeListener(myListenerImpl)otomatik olarak dinleyici kez kaldırılacak veya dinleyici tutan da bileşen kullanılamaz hale çünkü.

Tabii ki hala dinleyicinizi el ile kaldırabilirsiniz, ancak bunu unutmazsanız veya unutursanız, bellek sızıntısına neden olmaz ve dinleyicinizin çöp toplanmasını engellemez.

WeakHashMapResme nereden geliyor?

Kayıtlı dinleyicileri WeakReferences olarak saklamak isteyen dinleyici kayıt defteri, bu referansları saklamak için bir koleksiyona ihtiyaç duyar. WeakHashSetStandart Java kitaplığında yalnızca bir uygulama yoktur , WeakHashMapancak birincisinin işlevselliğini "uygulamak" için sonuncusunu kolayca kullanabiliriz:

Set<ListenerType> listenerSet =
    Collections.newSetFromMap(new WeakHashMap<ListenerType, Boolean>());

Bununla listenerSetyeni bir dinleyici kayıt sadece kümesine eklemek zorunda ve açıkça kaldırılır olmasa bile dinleyici artık başvuruda bulunulan, bu JVM tarafından otomatik olarak kaldırılacaktır.


10
Dinleyici listesi için poorHashSets kullanımıyla ilgili sorun, register () 'da oluşturulan anonim dinleyici örneklerinin kullanıcı tarafından beklenmedik şekilde kolayca kaybolmasıdır. Bunun yerine yöneticilerin dinleyicilerine daha güçlü referanslar vermek ve bunun yerine doğru şeyi yapmak için arayanlara güvenmek daha güvenlidir.
Gunanaresh

Dinleyici kayıt uygulaması için: Kayıtlı tüm dinleyiciler bir sonraki GC vuruşunda toplanacak / imha edilecek mi? Örneğin, tüm dinleyicilerin onSomethingHappened () yöntemini tetiklerken GC başladığında ne olur?
blackkara

@icza, insanların hala bu efsaneye alıştıklarına inanamıyorum. Bu tamamen yanlış bir cevap. Bir başka yararlı durumun WeakHashMap, bir HashMapnesneye ihtiyaç duyduğunuzda olduğunu da söyleyebilirsiniz . Vay be elle hashmap yapmak zorunda değilsiniz . Obj nesnesi kapsamı dışında kez öğeler otomatik olarak kaldırılır çünkü hiç kaldırmak! Kelimenin tam anlamıyla büyü! Böyle çirkin bir büyü kesmek tam bir facepalm .
Pacerier

3
@Pacerier: JavaScript in diğer yorumlarından bağlantılarınızı buraya kadar takip ettim ve WeakMap ile dinleyici kayıt defteri uygulamasının neden bir efsane olduğunu tam olarak anlayamıyorum. Örneğin, WebSocket istemcilerinin kayıt defteri hizmeti aracılığıyla üzerlerinde bazı dinleyicilerle bağlanması gerekiyorsa, soket nesnelerini WeakMap'te bir anahtar olarak depolamak mantıklı görünmektedir (bağlantı kapatıldıktan sonra bellekte asılı kalmalarını önlemek için) gerekirse tüm dinleyicilerini almak için. Peki, bu yaklaşımda tam olarak neyin yanlış olduğunu söyleyebilir misiniz?
Hasarlı Organik

1
@ Pacerer Ben de itirazınızı anlayamadım. Yayınlama-Abone Olma veya Olay Veri Yolu senaryosunda, zayıf başvurular benim için mükemmeldir. Abone olunan nesnenin, resmi olarak abonelikten çıkmaya gerek kalmadan kapsam dışına çıkmasına ve çöp toplama işlemine gitmesine izin verilir. Abonelikten çıkma süreci, üçüncü taraf bir nesne, abone olunan nesnenin bilgisi olmadan ilk abonelikten sorumluysa özellikle karmaşık olabilir. Koleksiyonu WeakReferencebüyük ölçüde kod tabanını basitleştiren ve çıkmak için başarısız ilgili gereksiz hatalar önler. Ne dezavantajı?
Basil Bourque

5

Bu blog gönderisi her iki sınıfın da kullanımını gösterir: Java: bir kimlik üzerinde eşitleme . Kullanım böyle bir şeye gider:

private static IdMutexProvider MUTEX_PROVIDER = new IdMutexProvider();

public void performTask(String resourceId) {
    IdMutexProvider.Mutex mutext = MUTEX_PROVIDER.getMutex(resourceId);
    synchronized (mutext) {
        // look up the resource and do something with it
    }
}

IdMutextProvider, senkronize edilecek kimlik tabanlı nesneler sağlar. Gereksinimler:

  • eşdeğer kimliklerin aynı anda kullanılması için aynı nesneye bir başvuru döndürmelidir
  • farklı kimlikler için farklı bir nesne döndürmelidir
  • serbest bırakma mekanizması yok (nesneler sağlayıcıya döndürülmez)
  • sızıntı yapmamalı (kullanılmayan nesneler çöp toplama için uygundur)

Bu, aşağıdaki türden bir dahili depolama haritası kullanılarak gerçekleştirilir:

WeakHashMap<Mutex, WeakReference<Mutex>>

Nesne hem anahtar hem de değerdir. Haritanın dışındaki hiçbir şeyin nesneye sert bir referansı yoksa, çöp toplanabilir. Haritadaki değerler sabit referanslarla saklanır, bu nedenle bellek sızıntısını önlemek için değerin bir WeakReference öğesine sarılması gerekir . Bu son nokta javadokta ele alınmıştır .


3

Örneğin, belirli bir sınıftan oluşturulan tüm nesneleri takip etmek istiyorsanız. Bu nesnelerin yine de çöp toplanmasına izin vermek için, nesnelerin kendileri yerine nesnelere zayıf referansların bir listesini / haritasını tutarsınız.

Şimdi birisi bana hayali referansları açıklayabilseydi, mutlu olurum ...


2
Bir kullanım: PhantomReferences bir nesnenin ne zaman bellekten kaldırıldığını belirlemenizi sağlar. Aslında bunu belirlemenin tek yolu onlar. ( weblogs.java.net/blog/enicholas/archive/2006/05/… )
Jacob Krall

Aslında, siz açıkça temizleyene kadar kaldırılmaz. "Yumuşak ve zayıf referansların aksine, fantom referansları, enküre edildikçe çöp toplayıcı tarafından otomatik olarak temizlenmez. Fantom referansları ile erişilebilen bir nesne, tüm bu referanslar temizlenene veya kendilerine ulaşılamaz hale gelene kadar aynı kalır."
jontro

@jontro, Ama zaten kesinleşmiş , tüm üyeler gitti. Etkili, boş bir obj. Bkz. Stackoverflow.com/q/7048767/632951
Pacerier

3

Yukarıda belirtildiği gibi, zayıf referans güçlü bir referans olduğu sürece tutulur.

Örnek bir kullanım, dinleyicilerin içinde WeakReference'ın kullanılmasıdır, böylece hedef nesnelerine ana başvuru gittikten sonra dinleyiciler artık etkin olmaz. Bunun WeakReference öğesinin dinleyiciler listesinden kaldırıldığı anlamına gelmediğini, temizleme işleminin hala gerekli olduğunu ancak örneğin planlanan zamanlarda gerçekleştirilebileceğini unutmayın. Bu aynı zamanda, dinlenen nesnenin güçlü referanslar tutmasını engelleme ve sonuçta bir bellek şişkinliği kaynağı olma etkisine de sahiptir. Örnek: GUI bileşenlerini, pencereden daha uzun bir yaşam döngüsüne sahip bir modeli referans alan salıncak.

Yukarıda açıklandığı gibi dinleyicilerle oynarken, nesnelerin bir kullanıcının bakış açısından "hemen" toplandığını hızla fark ettik.


Teşekkürler yararlı cevap. Ama merak ediyorum, bu durumda, dinleyiciler güçlü bir şekilde kaydedilmeli (referans gösterilmelidir)?
blackkara

Bu cevap tamamen yanlış.
Detaylandırma

@Pacerier - WeakReferencesyorumunuz için tamamen yanlış!

2

WeakReferences için kullandığım bir gerçek dünya kullanımı, nadiren kullanılan tek, çok büyük bir nesneniz varsa. Gerekmediğinde hafızada tutmak istemezsiniz; ancak başka bir iş parçacığının aynı nesneye ihtiyacı varsa, ikisinin de bellekte olmasını istemezsiniz. Bir yerde nesneye zayıf bir referans ve onu kullanan yöntemlerde sert referanslar tutabilirsiniz; yöntemlerin ikisi de bittiğinde, nesne toplanacaktır.


1
Bu bir zayıf referans, zayıf bir referans değil. Bkz. Stackoverflow.com/a/155492/632951
Pacerier


-1

geniş nesne oluşturma için kaynaksız bir önbellek uygulamak için poorhashmap kullanabilirsiniz.

ancak değişken nesnelerin olması arzu edilmez. i nadiren güncellenen bir metin arama motoru, sorgu sonuçlarını (yürütmek için yaklaşık 400 ms sürer) önbellek için kullanılır.


Bir zayıf referanstan bahsediyorsun, zayıf bir referanstan değil. Bkz. Stackoverflow.com/a/155492/632951
Pacerier
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.