Biarkan saya mengeluarkan ini dulu dan kembali ke sana:
WeakReference berguna ketika Anda ingin mengawasi objek, tetapi Anda TIDAK ingin pengamatan Anda untuk mencegah objek itu dikumpulkan
Jadi mari kita mulai dari awal:
- maaf sebelumnya untuk setiap pelanggaran yang tidak disengaja, tapi aku akan kembali ke level "Dick dan Jane" untuk sesaat karena seseorang tidak akan pernah bisa memberitahu audiensnya.
Jadi, ketika Anda punya objek X
- mari kita tentukan itu sebagai contoh class Foo
- itu TIDAK BISA hidup sendiri (sebagian besar benar); Dengan cara yang sama bahwa "Tidak ada manusia adalah sebuah pulau", hanya ada beberapa cara agar suatu objek dapat dipromosikan menjadi Pulau - meskipun itu disebut sebagai akar GC dalam CLR berbicara. Menjadi Root GC, atau memiliki rantai koneksi / referensi ke root GC, pada dasarnya adalah apa yang menentukan apakah Foo x = new Foo()
sampah dikumpulkan atau tidak .
Jika Anda tidak dapat berjalan kembali ke root GC baik dengan menumpuk atau menumpuk berjalan, Anda menjadi yatim secara efektif, dan kemungkinan akan ditandai / dikumpulkan siklus berikutnya.
Pada titik ini, mari kita lihat beberapa contoh yang mengerikan:
Pertama, kami 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--);
}
}
Cukup sederhana - ini bukan utas yang aman, jadi jangan coba-coba itu, tetapi simpan "jumlah referensi" kasar dari contoh dan pengurangan aktif saat selesai.
Sekarang mari kita lihat 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");
}
}
Jadi kita punya objek yang sudah menjadi root GC sendiri (yah ... lebih spesifik, itu akan di-root melalui rantai langsung ke domain aplikasi yang menjalankan aplikasi ini, tapi itu topik lain) yang memiliki dua metode menempel ke Foo
contoh - mari kita mengujinya:
// 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();
Sekarang, dari yang di atas, apakah Anda berharap objek-yang-pernah-disebut-oleh f
itu "bisa dikoleksi"?
Tidak, karena ada objek lain sekarang memegang referensi untuk itu - Dictionary
dalam Singleton
contoh statis itu.
Ok, mari kita coba pendekatan yang lemah:
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();
Sekarang, ketika kita memukul referensi kita ke Foo
-yang-itu-sekali- f
, tidak ada lagi referensi "keras" untuk objek, jadi itu bisa dikoleksi - yang WeakReference
dibuat oleh pendengar yang lemah tidak akan mencegah itu.
Kasus penggunaan yang baik:
Penangan acara (Meskipun membaca ini dulu: Lemahnya Acara di C # )
Anda punya situasi di mana Anda akan menyebabkan "referensi rekursif" (yaitu, objek A merujuk ke objek B, yang mengacu pada objek A, juga disebut sebagai "Memory Leak") (edit: derp, tentu saja ini bukan itu benar)
Anda ingin "menyiarkan" sesuatu ke koleksi objek, tetapi Anda tidak ingin menjadi benda yang membuat mereka tetap hidup; a List<WeakReference>
dapat dipertahankan dengan mudah, dan bahkan dipangkas dengan menghapus di manaref.Target == null