Saya belum menemukan situasi di mana saya harus menggunakan tipe WeakReference di .Net, tetapi kepercayaan yang populer sepertinya harus digunakan dalam cache. Dr Jon Harrop memberikan kasus yang sangat baik terhadap penggunaan WeakReferences di cache dalam bukunya jawaban untuk ini pertanyaan.
Saya juga sering mendengar pengembang AS3 berbicara tentang menggunakan referensi yang lemah untuk menghemat jejak memori tetapi berdasarkan percakapan saya sepertinya menambah kompleksitas tanpa harus mencapai tujuan yang diinginkan, dan perilaku runtime agak tidak dapat diprediksi. Sedemikian rupa sehingga banyak yang menyerah dan mengelola penggunaan memori dengan lebih hati-hati / mengoptimalkan kode mereka menjadi kurang intensif memori (atau membuat trade-off lebih banyak siklus CPU dan jejak memori yang lebih kecil).
Dr Jon Harrop juga menunjukkan dalam jawabannya bahwa referensi lemah. Net tidak lunak, dan ada koleksi agresif referensi lemah di gen0. Menurut MSDN , referensi panjang yang lemah memberi Anda potensi untuk membuat ulang objek but the state of the object remains unpredictable.
,!
Mengingat karakteristik ini, saya tidak dapat memikirkan situasi di mana referensi yang lemah akan berguna, mungkin seseorang dapat mencerahkan saya?
sumber
Jawaban:
Saya telah menemukan aplikasi praktis yang sah dari referensi yang lemah dalam tiga skenario dunia nyata berikut yang sebenarnya terjadi pada saya secara pribadi:
Aplikasi 1: Penangan acara
Anda seorang pengusaha. Perusahaan Anda menjual kontrol jalur percikan untuk WPF. Penjualan besar tetapi biaya dukungan membunuh Anda. Terlalu banyak pelanggan mengeluh tentang CPU hogging dan kebocoran memori ketika mereka menggulir layar penuh garis percikan. Masalahnya adalah aplikasi mereka membuat garis percikan baru saat mereka terlihat tetapi pengikatan data mencegah yang lama dikumpulkan. Apa yang kamu kerjakan?
Memperkenalkan referensi yang lemah antara pengikatan data dan kontrol Anda sehingga pengikatan data saja tidak akan lagi mencegah kontrol Anda dari pengumpulan sampah. Kemudian tambahkan finalizer ke kontrol Anda yang meruntuhkan ikatan data saat dikumpulkan.
Aplikasi 2: Grafik yang dapat diubah
Anda adalah John Carmack berikutnya. Anda telah menemukan representasi berbasis grafik baru dari permukaan subdivisi hirarkis yang membuat permainan Tim Sweeney terlihat seperti Nintendo Wii. Jelas saya tidak akan memberi tahu Anda dengan tepat bagaimana cara kerjanya tetapi semuanya berpusat pada grafik yang bisa berubah ini di mana tetangga dari sebuah simpul dapat ditemukan di a
Dictionary<Vertex, SortedSet<Vertex>>
. Topologi grafik terus berubah saat pemain berputar. Hanya ada satu masalah: struktur data Anda menumpahkan subgraph yang tidak dapat dijangkau saat dijalankan dan Anda harus menghapusnya atau Anda akan membocorkan memori. Untungnya Anda jenius sehingga Anda tahu ada kelas algoritma yang dirancang khusus untuk mencari dan mengumpulkan subgraph yang tidak dapat dijangkau: pengumpul sampah! Anda membaca monografi luar biasa Richard Jones tentang masalah initetapi itu membuat Anda bingung dan khawatir tentang tenggat waktu Anda yang sudah dekat. Apa yang kamu kerjakan?Cukup dengan mengganti
Dictionary
tabel hash Anda dengan lemah, Anda dapat mendukung GC yang ada dan memilikinya secara otomatis mengumpulkan subgraf yang tidak dapat dijangkau untuk Anda! Kembali ke membalik-balik iklan Ferrari.Aplikasi 3: Dekorasi pohon
Anda tergantung dari langit-langit ruang cyclindrical di keyboard. Anda punya 60 detik untuk menyaring beberapa DATA BESAR sebelum seseorang menemukan Anda. Anda datang dipersiapkan dengan parser berbasis aliran yang indah yang mengandalkan GC untuk mengumpulkan fragmen AST setelah dianalisis. Tetapi Anda menyadari bahwa Anda membutuhkan metadata tambahan pada setiap AST
Node
dan Anda membutuhkannya dengan cepat. Apa yang kamu kerjakan?Anda bisa menggunakan a
Dictionary<Node, Metadata>
untuk mengaitkan metadata dengan setiap node tetapi, kecuali Anda menghapusnya, referensi kuat dari kamus ke node AST lama akan membuatnya tetap hidup dan membocorkan memori. Solusinya adalah tabel hash yang lemah yang hanya menyimpan referensi lemah untuk kunci dan sampah mengumpulkan ikatan nilai kunci ketika kunci menjadi tidak terjangkau. Kemudian, ketika AST node menjadi tidak terjangkau mereka mengumpulkan sampah dan mengikat nilai kunci mereka dihapus dari kamus meninggalkan metadata yang sesuai tidak terjangkau sehingga juga dikumpulkan. Maka yang harus Anda lakukan setelah loop utama Anda berakhir adalah meluncur ke atas melalui lubang udara mengingat untuk menggantinya tepat ketika penjaga keamanan masuk.Perhatikan bahwa dalam ketiga aplikasi dunia nyata ini yang benar-benar terjadi pada saya, saya ingin GC mengumpulkan seagresif mungkin. Itu sebabnya ini adalah aplikasi yang sah. Semua orang salah.
sumber
ConditionalWeakTable
dalam. NET).ConditionalWeakTable
itulah yang akan digunakan aplikasi 2 dan 3 sedangkan beberapa orang di postingan lain benar-benar menggunakannyaDictionary<WeakReference, T>
. Tidak tahu mengapa — Anda selalu berakhir dengan satu ton nolWeakReference
dengan nilai yang tidak dapat diakses oleh tombol apa pun terlepas dari bagaimana Anda melakukannya. Ridik.Dokumen Microsoft, Pola Kejadian Lemah .
sumber
Biarkan saya mengeluarkan ini dulu dan kembali ke sana:
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 contohclass 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 apakahFoo 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
: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
: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: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
dalamSingleton
contoh statis itu.Ok, mari kita coba pendekatan yang lemah:
Sekarang, ketika kita memukul referensi kita ke
Foo
-yang-itu-sekali-f
, tidak ada lagi referensi "keras" untuk objek, jadi itu bisa dikoleksi - yangWeakReference
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
sumber
Seperti kebocoran logis yang benar-benar sulit dilacak sementara pengguna cenderung memperhatikan bahwa menjalankan perangkat lunak Anda untuk waktu yang lama cenderung mengambil lebih banyak dan lebih banyak memori dan semakin lama semakin lambat hingga mereka mulai ulang? Bukan saya.
Pertimbangkan apa yang terjadi jika, ketika pengguna meminta untuk menghapus sumber daya aplikasi di atas,
Thing2
gagal untuk menangani peristiwa semacam itu di bawah:... dan di mana salah satu dari kesalahan semacam itu kemungkinan akan ditangkap selama pengujian, dan mana yang tidak akan dan akan terbang di bawah radar seperti bug pejuang siluman. Kepemilikan bersama, lebih sering daripada kebanyakan, adalah ide yang tidak masuk akal.
sumber
Contoh yang sangat ilustratif dari referensi lemah yang digunakan untuk efek yang baik adalah ConditionalWeakTable , yang digunakan oleh DLR (di antara tempat-tempat lain) untuk melampirkan "anggota" tambahan ke objek.
Anda tidak ingin tabel menjaga objek tetap hidup. Konsep ini tidak dapat bekerja tanpa referensi yang lemah.
Tapi sepertinya bagi saya bahwa semua penggunaan untuk referensi yang lemah datang lama setelah mereka ditambahkan ke bahasa, karena referensi yang lemah telah menjadi bagian dari .NET sejak versi 1.1. Sepertinya sesuatu yang ingin Anda tambahkan, sehingga kurangnya kehancuran deterministik tidak akan mendukung Anda sejauh menyangkut fitur bahasa.
sumber
WeakReference
tipe, karena situasinya jauh lebih kompleks. Ini menggunakan berbagai fungsi yang diekspos oleh CLR.Jika Anda memiliki lapisan cache diimplementasikan dengan C # itu jauh lebih baik juga meletakkan data Anda dalam cache sebagai referensi lemah, itu bisa membantu untuk meningkatkan kinerja lapisan cache Anda.
Pikirkan bahwa pendekatan juga dapat diterapkan pada implementasi sesi. Karena sesi adalah objek yang panjang, sebagian besar waktu, bisa jadi kasus ketika Anda tidak memiliki memori untuk pengguna baru. Dalam hal ini akan jauh lebih baik untuk menghapus beberapa objek sesi pengguna lain kemudian membuang OutOfMemoryException.
Juga, jika Anda memiliki objek besar dalam aplikasi Anda (beberapa tabel pencarian besar, dll), yang harus digunakan sangat jarang dan membuat ulang objek seperti itu bukanlah prosedur yang sangat mahal. Maka lebih baik memilikinya seperti referensi seminggu untuk memiliki cara untuk membebaskan memori Anda ketika Anda benar-benar membutuhkannya.
sumber