Haruskah pendengar acara diadakan dalam referensi yang lemah?

9

Biasanya pendengar acara tidak boleh hidup lebih lama dari objek yang mendaftarkan mereka.

Apakah ini berarti bahwa pendengar acara harus dipegang oleh referensi lemah secara default (disimpan dalam koleksi lemah oleh objek yang didaftarkan oleh pendengar objek)?

Apakah ada kasus yang valid ketika pendengar harus hidup lebih lama dari penciptanya?

Atau mungkin situasi seperti itu adalah kesalahan dan itu seharusnya tidak diizinkan?

mrpyo
sumber
Referensi yang lemah biasanya diwakili oleh contoh, dan contoh ini juga dapat terakumulasi ke titik di mana mereka harus dikumpulkan sebagai sampah. Jadi ini bukan makan siang gratis. Logika yang sama yang membersihkan referensi yang lemah bisa membersihkan referensi yang kuat.
Frank Hileman

Jawaban:

7

Mengapa pendengar acara tidak hidup lebih lama dari objek yang mendaftarkannya? Sepertinya Anda mengasumsikan pendengar acara harus terdaftar dengan metode kontrol (jika kita mengambil contoh GUI) - atau lebih tepatnya, metode dengan objek kelas yang mewarisi kontrol toolkit GUI. Itu bukan keharusan - Anda dapat, misalnya, menggunakan objek khusus untuk mendaftarkan pendengar acara dan membuang objek itu sesudahnya.

Juga, jika pendengar acara dirujuk dengan lemah, Anda harus benar-benar menyimpan referensi kepada mereka bahkan jika Anda tidak pernah menggunakan referensi itu. Gagal melakukannya akan membuat pendengar dikumpulkan secara acak. Jadi, kami mendapatkan bug itu

  • Mudah dibuat secara tidak sengaja (yang harus Anda lakukan adalah lupa menyimpan objek dalam variabel referensi yang tidak akan pernah Anda gunakan).
  • Sulit diketahui (Anda hanya akan mendapatkan bug itu jika GC mengumpulkan objek itu).
  • Sulit di-debug (dalam sesi debug - yang selalu berfungsi seperti sesi rilis - Anda hanya akan menemukan bug jika GC mengumpulkan objek).

Dan jika menghindari bug itu insentif yang tidak cukup baik, berikut adalah beberapa lebih banyak:

  1. Anda harus memikirkan nama untuk setiap pendengar yang Anda buat.

  2. Beberapa bahasa menggunakan analisis statis yang akan menghasilkan peringatan jika Anda memiliki bidang anggota pribadi yang tidak pernah ditulis atau tidak pernah dibaca. Anda harus menggunakan mekanisme untuk menimpanya.

  3. Pendengar acara melakukan sesuatu, dan sekali objek yang memiliki referensi kuat dikumpulkan, ia akan berhenti melakukan sesuatu itu. Anda sekarang memiliki sesuatu yang mempengaruhi keadaan program dan tergantung pada GC - yang berarti GC mempengaruhi keadaan konkret program. Dan ini BURUK !

  4. Menangani referensi yang lemah lebih lambat, karena Anda memiliki tingkat tipuan yang lain dan karena Anda perlu memeriksa apakah referensi tersebut dikumpulkan. Ini tidak akan menjadi masalah jika memiliki pendengar acara dalam referensi lemah diperlukan - tetapi tidak!

Idan Arye
sumber
5

Secara umum, ya, referensi yang lemah harus digunakan. Tapi pertama-tama kita harus jelas tentang apa yang Anda maksud dengan "pendengar acara".

Telepon balik

Dalam beberapa gaya pemrograman, terutama dalam konteks operasi asinkron, biasanya merupakan bagian dari perhitungan sebagai panggilan balik yang dijalankan pada peristiwa tertentu. Misalnya a Promise[ 1 ] mungkin memiliki thenmetode yang mendaftarkan panggilan balik setelah menyelesaikan langkah sebelumnya:

promise =
    Promise.new(async_task)                # - kick off a task
    .then(value => operation_on(value))    # - queue other operations
    .then(value => other_operation(value)) #   that get executed on completion
... # do other stuff in the meanwhile
# later:
result = promise.value # block for the result

Di sini, callback yang terdaftar thenharus dipegang oleh referensi yang kuat, karena janji (sumber acara) adalah satu-satunya objek yang memegang referensi ke callback. Ini bukan masalah karena janji itu sendiri memiliki masa hidup yang terbatas, dan akan menjadi sampah yang dikumpulkan setelah rantai janji selesai.

Pola Pengamat

Dalam pola pengamat, subjek memiliki daftar pengamat dependen. Ketika subjek memasuki beberapa keadaan, pengamat diberitahu sesuai dengan beberapa antarmuka. Pengamat dapat ditambahkan dan dihapus dari subjek. Pengamat ini tidak ada dalam kekosongan semantik, tetapi sedang menunggu acara untuk beberapa tujuan.

Jika tujuan ini tidak ada lagi, pengamat harus dihapus dari subjek. Bahkan dalam bahasa yang dikumpulkan sampah, penghapusan ini mungkin harus dilakukan secara manual. Jika kita gagal menghapus pengamat, itu akan tetap hidup melalui referensi dari subjek ke pengamat, dan dengan itu semua objek yang dirujuk oleh pengamat. Ini membuang-buang memori dan menurunkan kinerja sebagai pengamat (sekarang tidak berguna) masih akan diberitahu.

Referensi yang lemah memperbaiki kebocoran memori ini, karena memungkinkan pengamat mengumpulkan sampah. Ketika subjek berkeliling untuk memberi tahu semua pengamat dan menemukan bahwa salah satu referensi lemah ke pengamat kosong, referensi itu dapat dihapus dengan aman. Sebagai alternatif, referensi yang lemah dapat diimplementasikan dengan cara yang memungkinkan subjek untuk mendaftarkan panggilan pembersihan yang akan menghapus pengamat setelah pengumpulan.

Tetapi perhatikan bahwa referensi yang lemah hanyalah bantuan pita yang membatasi kerusakan dengan lupa untuk memindahkan pengamat. Solusi yang tepat adalah memastikan bahwa seorang pengamat dihapus ketika tidak lagi diperlukan. Opsi meliputi:

  • Melakukannya secara manual, tapi itu rawan kesalahan.

  • Menggunakan sesuatu yang mirip dengan coba-dengan-sumber daya di Jawa atau usingdi C #.

  • Kehancuran deterministik, seperti melalui idiom RAII. Perhatikan bahwa dalam bahasa dengan pengumpulan sampah deterministik, ini mungkin masih membutuhkan referensi yang lemah dari subjek ke pengamat untuk memicu destruktor.

amon
sumber