Önce bunu ortaya koyalım ve geri dönelim:
Bir Nesnede sekmeleri tutmak istediğinizde WeakReference kullanışlıdır, ancak gözlemlerinizin nesnenin toplanmasını önlemesini istemezsiniz.
Öyleyse baştan başlayalım:
- kasıtsız herhangi bir suç için önceden teknolojiler, ancak bir kimseye hiç kimseye söyleyemediğinden, bir anlığına "Dick and Jane" seviyesine geri döneceğim.
Öyleyse bir nesneniz olduğunda X
- bunu bir örnek olarak belirleyelim class Foo
- kendi başına yaşayamaz (çoğunlukla doğru); Aynı şekilde, "Hiçbir erkek bir ada değildir", bir nesnenin Adalığa terfi edebileceği birkaç yol vardır - bununla birlikte CLR konuşmasında GC kökü olarak adlandırılır. Bir GC Kökü olmak veya bir GC köküne köklü bir bağlantı / referans zincirine sahip olmak temel olarak Foo x = new Foo()
çöpün toplanıp toplanmayacağını belirleyen şeydir .
Yığın veya yığın yürüyüşü yoluyla bazı GC köklerine geri gidemiyorsanız, etkili bir şekilde yetim kaldınız ve büyük olasılıkla bir sonraki döngüde işaretlenecek / toplanacaksınız.
Bu noktada, bazı korkunç içerikli örnekleri inceleyelim:
İlk olarak, bizim Foo
:
public class Foo
{
private static volatile int _ref = 0;
public event EventHandler FooEvent;
public Foo()
{
_ref++;
Console.WriteLine("I am #{0}", _ref);
}
~Foo()
{
Console.WriteLine("#{0} dying!", _ref--);
}
}
Oldukça basit - iş parçacığı güvenli değildir, bu yüzden bunu denemeyin, ancak sonlandırıldığında aktif örneklerin ve düşüşlerin kaba bir "referans sayısını" korur.
Şimdi bir bakalım FooConsumer
:
public class NastySingleton
{
// Static member status is one way to "get promoted" to a GC root...
private static NastySingleton _instance = new NastySingleton();
public static NastySingleton Instance { get { return _instance;} }
// testing out "Hard references"
private Dictionary<Foo, int> _counter = new Dictionary<Foo,int>();
// testing out "Weak references"
private Dictionary<WeakReference, int> _weakCounter = new Dictionary<WeakReference,int>();
// Creates a strong link to Foo instance
public void ListenToThisFoo(Foo foo)
{
_counter[foo] = 0;
foo.FooEvent += (o, e) => _counter[foo]++;
}
// Creates a weak link to Foo instance
public void ListenToThisFooWeakly(Foo foo)
{
WeakReference fooRef = new WeakReference(foo);
_weakCounter[fooRef] = 0;
foo.FooEvent += (o, e) => _weakCounter[fooRef]++;
}
private void HandleEvent(object sender, EventArgs args, Foo originalfoo)
{
Console.WriteLine("Derp");
}
}
Bu yüzden zaten kendi GC kökünün bir nesnesine sahibiz (peki ... spesifik olarak, bu uygulamayı çalıştıran uygulama etki alanına doğrudan bir zincir yoluyla köklenecek, ancak bu iki yöntemi olan) bir Foo
örneğe mandalla - hadi deneyelim:
// Our foo
var f = new Foo();
// Create a "hard reference"
NastySingleton.Instance.ListenToThisFoo(f);
// Ok, we're done with this foo
f = null;
// Force collection of all orphaned objects
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Şimdi, yukarıdan, bir zamanlar denilen nesnenin f
“toplanabilir” olmasını bekler miydiniz ?
Hayır, çünkü artık ona referans tutan başka bir nesne var - Dictionary
o Singleton
statik durumda.
Tamam, zayıf yaklaşımı deneyelim:
f = new Foo();
NastySingleton.Instance.ListenToThisFooWeakly(f);
// Ok, we're done with this foo
f = null;
// Force collection of all orphaned objects
// This should collect # 2 - you'll see a "#2 dying"
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Şimdi, bir zamanlar olan -e Foo
-bir kez oldu- referansımıza vurduğumuzda f
, nesneye daha fazla "sert" referanslar kalmıyor, bu yüzden koleksiyon yapılabilir - WeakReference
zayıf dinleyicinin yaratması bunu engellemeyecek.
İyi kullanım durumları:
Olay işleyicileri (İlk önce bunu okumasına rağmen: C #'daki Zayıf Olaylar )
Bir “özyinelemeli referans” (yani, A nesnesi, aynı zamanda “Bellek Sızıntısı” olarak da adlandırılan A nesnesini ifade eder, A nesnesini ifade eder) neden olacağınız bir durumunuz var (düzenleme: derp, elbette bu doğru değil)
Bir şeyleri bir koleksiyona "yayınlamak" istiyorsunuz, ancak onları canlı tutan şey olmak istemiyorsunuz; a List<WeakReference>
kolayca tutulabilir ve hatta çıkarılarak budanabilirref.Target == null