Pendeknya
Finalisasi bukan masalah sederhana untuk ditangani oleh pemulung. Mudah digunakan dengan referensi penghitungan GC, tetapi keluarga GC ini sering tidak lengkap, membutuhkan kebocoran memori untuk dikompensasi oleh pemicu eksplisit penghancuran dan finalisasi beberapa objek dan struktur. Melacak pengumpul sampah jauh lebih efektif, tetapi mereka membuat lebih sulit untuk mengidentifikasi objek yang akan diselesaikan dan dihancurkan, bukan hanya mengidentifikasi memori yang tidak terpakai, sehingga membutuhkan manajemen yang lebih kompleks, dengan biaya dalam waktu dan ruang, dan dalam kompleksitas pelaksanaan.
pengantar
Saya berasumsi bahwa apa yang Anda tanyakan adalah mengapa bahasa sampah yang dikumpulkan tidak secara otomatis menangani kehancuran / finalisasi dalam proses pengumpulan sampah, seperti yang ditunjukkan oleh komentar:
Saya merasa sangat kurang bahwa bahasa-bahasa ini menganggap memori sebagai satu-satunya sumber daya yang layak dikelola. Bagaimana dengan soket, pegangan file, status aplikasi?
Saya tidak setuju dengan jawaban yang diterima yang diberikan oleh kdbanman . Sementara fakta-fakta yang disebutkan sebagian besar benar, meskipun sangat bias terhadap penghitungan referensi, saya tidak percaya mereka menjelaskan dengan tepat situasi yang dikeluhkan dalam pertanyaan.
Saya tidak percaya bahwa terminologi yang dikembangkan dalam jawaban itu jauh dari masalah, dan lebih cenderung membingungkan. Memang, sebagaimana disajikan, terminologi sebagian besar ditentukan oleh cara prosedur diaktifkan daripada oleh apa yang mereka lakukan. Intinya adalah bahwa dalam semua kasus, ada kebutuhan untuk menyelesaikan suatu objek tidak lagi diperlukan dengan beberapa proses pembersihan dan untuk membebaskan sumber daya apa pun yang telah digunakan, memori menjadi salah satunya. Idealnya, semua itu harus dilakukan secara otomatis ketika objek tidak lagi digunakan, melalui pengumpul sampah. Dalam praktiknya, GC mungkin hilang atau memiliki kekurangan, dan ini dikompensasikan dengan dipicu secara eksplisit oleh program finalisasi dan reklamasi.
Trigerring eksplisit oleh program adalah masalah karena hal itu memungkinkan untuk sulit menganalisis kesalahan pemrograman, ketika suatu objek yang masih digunakan sedang dihentikan secara eksplisit.
Oleh karena itu jauh lebih baik untuk mengandalkan pengumpulan sampah otomatis untuk mendapatkan kembali sumber daya. Tetapi ada dua masalah:
beberapa teknik pengumpulan sampah akan memungkinkan kebocoran memori yang mencegah reklamasi penuh sumber daya. Ini terkenal untuk referensi penghitungan GC, tetapi mungkin muncul untuk teknik GC lainnya ketika menggunakan beberapa organisasi data tanpa perawatan (poin tidak dibahas di sini).
sementara teknik GC mungkin baik dalam mengidentifikasi sumber daya memori tidak lagi digunakan, menyelesaikan objek yang terkandung di dalamnya mungkin tidak sederhana, dan yang mempersulit masalah reklamasi sumber daya lain yang digunakan oleh objek-objek ini, yang sering kali merupakan tujuan finalisasi.
Akhirnya, poin penting yang sering dilupakan adalah bahwa siklus GC dapat dipicu oleh apa saja, bukan hanya kekurangan memori, jika kait yang tepat disediakan dan jika biaya siklus GC dianggap layak. Oleh karena itu, boleh saja memulai GC ketika sumber daya apa pun hilang, dengan harapan membebaskan sebagian.
Referensi penghitungan pemulung
Penghitungan referensi adalah teknik pengumpulan sampah yang lemah , yang tidak akan menangani siklus dengan baik. Memang akan lemah dalam menghancurkan struktur usang, dan merebut kembali sumber daya lainnya hanya karena lemah pada reklamasi memori. Tetapi finalizer dapat digunakan dengan paling mudah dengan referensi penghitungan pengumpulan sampah (GC), karena penghitungan ulang GC memang mengklaim kembali suatu struktur ketika penghitungan refnya turun ke 0, di mana saat itu alamatnya diketahui bersama-sama dengan tipenya, baik secara statis atau secara dinamis. Oleh karena itu dimungkinkan untuk mendapatkan kembali memori tepat setelah menerapkan finalizer yang tepat, dan memanggil proses secara rekursif pada semua objek yang ditunjuk (mungkin melalui prosedur finalisasi).
Singkatnya, finalisasi mudah diterapkan dengan Ref Counting GC, tetapi menderita dari "ketidaklengkapan" dari GC itu, memang karena struktur melingkar, sampai pada tingkat yang sama persis dengan yang diderita reklamasi memori. Dengan kata lain, dengan jumlah referensi, memori justru dikelola dengan buruk seperti sumber daya lain seperti soket, pegangan file, dll.
Memang, Ref Count GC ketidakmampuan untuk mengklaim kembali struktur perulangan (secara umum) dapat dilihat sebagai kebocoran memori . Anda tidak dapat mengharapkan semua GC untuk menghindari kebocoran memori. Itu tergantung pada algoritma GC, dan pada tipe struktur informasi yang tersedia secara dinamis (misalnya dalam
GC konservatif ).
Melacak pengumpul sampah
Keluarga GC yang lebih kuat, tanpa kebocoran seperti itu, adalah keluarga penelusuran yang mengeksplorasi bagian-bagian langsung dari memori, dimulai dari petunjuk root yang teridentifikasi dengan baik. Semua bagian memori yang tidak dikunjungi dalam proses penelusuran ini (yang sebenarnya dapat didekomposisi dengan berbagai cara, tetapi saya harus menyederhanakan) adalah bagian memori yang tidak digunakan yang dapat dengan demikian direklamasi 1 . Kolektor ini akan mendapatkan kembali semua bagian memori yang tidak lagi dapat diakses oleh program, apa pun fungsinya. Itu memang mengklaim kembali struktur lingkaran, dan GC yang lebih maju didasarkan pada beberapa variasi dari paradigma ini, kadang-kadang sangat canggih. Ini dapat dikombinasikan dengan penghitungan referensi dalam beberapa kasus, dan mengimbangi kelemahannya.
Masalahnya adalah pernyataan Anda (di akhir pertanyaan):
Bahasa yang menawarkan pengumpulan sampah otomatis tampaknya menjadi kandidat utama untuk mendukung penghancuran / penyelesaian objek karena mereka tahu dengan kepastian 100% ketika suatu objek tidak lagi digunakan.
secara teknis tidak benar untuk melacak kolektor.
Yang diketahui dengan kepastian 100% adalah bagian memori mana yang tidak lagi digunakan . (Lebih tepatnya, harus dikatakan bahwa mereka tidak lagi dapat diakses , karena beberapa bagian, yang tidak lagi dapat digunakan sesuai dengan logika program, masih dianggap digunakan jika masih ada pointer yang tidak berguna untuk mereka dalam program. data.) Tetapi pemrosesan lebih lanjut dan struktur yang sesuai diperlukan untuk mengetahui benda apa yang tidak terpakai yang mungkin telah disimpan di bagian memori yang sekarang tidak digunakan . Ini tidak dapat ditentukan dari apa yang diketahui dari program, karena program tidak lagi terhubung ke bagian memori ini.
Dengan demikian setelah melewati pengumpulan sampah, Anda dibiarkan dengan fragmen memori yang berisi benda-benda yang tidak lagi digunakan, tetapi ada apriori tidak ada cara untuk mengetahui apa objek-objek ini sehingga dapat menerapkan finalisasi yang benar. Selanjutnya, jika kolektor pelacak adalah tipe mark-and-sweep, mungkin beberapa fragmen mungkin berisi objek yang telah diselesaikan dalam lintasan GC sebelumnya, tetapi tidak digunakan karena alasan fragmentasi. Namun ini bisa diatasi dengan menggunakan pengetikan eksplisit yang diperluas.
Sementara seorang kolektor sederhana hanya akan mengklaim kembali fragmen memori ini, tanpa basa-basi lagi, finalisasi memerlukan izin khusus untuk mengeksplorasi memori yang tidak terpakai, mengidentifikasi objek yang ada di dalamnya, dan menerapkan prosedur finalisasi. Tetapi eksplorasi semacam itu membutuhkan penentuan jenis objek yang disimpan di sana, dan penentuan jenis juga diperlukan untuk menerapkan finalisasi yang tepat, jika ada.
Sehingga menyiratkan biaya tambahan dalam waktu GC (pass tambahan) dan mungkin biaya memori tambahan untuk membuat informasi jenis yang tepat tersedia selama melewati dengan berbagai teknik. Biaya-biaya ini mungkin signifikan karena kita sering ingin menyelesaikan hanya beberapa objek, sementara waktu dan ruang overhead dapat menyangkut semua objek.
Poin lain adalah bahwa waktu dan ruang overhead mungkin menyangkut eksekusi kode program, dan bukan hanya eksekusi GC.
Saya tidak dapat memberikan jawaban yang lebih tepat, menunjuk pada masalah tertentu, karena saya tidak tahu secara spesifik banyak bahasa yang Anda daftarkan. Dalam kasus C, mengetik adalah masalah yang sangat sulit yang mengarah pada pengembangan kolektor konservatif. Dugaan saya adalah bahwa ini juga mempengaruhi C ++, tapi saya bukan ahli C ++. Ini sepertinya dikonfirmasi oleh Hans Boehm yang melakukan banyak penelitian tentang GC konservatif. GC konservatif tidak dapat mengklaim kembali secara sistematis semua memori yang tidak digunakan secara tepat karena mungkin kekurangan informasi jenis yang tepat pada data. Untuk alasan yang sama, tidak akan dapat secara sistematis menerapkan prosedur penyelesaian.
Jadi, dimungkinkan untuk melakukan apa yang Anda minta, seperti yang Anda tahu dari beberapa bahasa. Tetapi itu tidak datang secara gratis. Bergantung pada bahasa dan implementasinya, mungkin memerlukan biaya bahkan ketika Anda tidak menggunakan fitur. Berbagai teknik dan trade-off dapat dipertimbangkan untuk mengatasi masalah ini, tetapi itu berada di luar cakupan jawaban yang cukup masuk akal.
1 - ini adalah presentasi abstrak dari tracing collection (mencakup baik copy dan mark-and-sweep GC), berbagai hal berbeda sesuai dengan jenis tracing collector, dan menjelajahi bagian memori yang tidak digunakan berbeda, tergantung pada apakah copy atau mark dan sapuan digunakan.
finalize
/destroy
adalah dusta? Tidak ada jaminan itu akan pernah dieksekusi. Dan, bahkan jika, Anda tidak tahu kapan (diberi pengumpulan sampah otomatis), dan jika konteks yang diperlukan masih ada (mungkin sudah dikumpulkan). Jadi lebih aman untuk memastikan keadaan yang konsisten dengan cara lain, dan orang mungkin ingin memaksa programmer untuk melakukannya.