Mencari wawasan tentang keputusan seputar desain bahasa sampah yang dikumpulkan. Mungkin seorang pakar bahasa bisa mencerahkan saya? Saya berasal dari latar belakang C ++, jadi area ini membingungkan saya.
Tampaknya hampir semua sampah modern mengumpulkan bahasa dengan dukungan objek OOPy seperti Ruby, Javascript / ES6 / ES7, Actionscript, Lua, dll. Sepenuhnya menghilangkan paradigma destruktor / finalisasi. Python tampaknya menjadi satu-satunya dengan class __del__()
metodenya. Kenapa ini? Apakah ada keterbatasan fungsional / teoritis dalam bahasa dengan pengumpulan sampah otomatis yang mencegah penerapan metode destruktor / finalisasi objek yang efektif?
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? Tanpa kemampuan untuk mengimplementasikan logika kustom untuk membersihkan sumber daya non-memori dan menyatakan pada penyelesaian objek, saya diharuskan untuk membuang sampah aplikasi saya dengan myObject.destroy()
panggilan gaya kustom , menempatkan logika pembersihan di luar "kelas" saya, memecahkan enkapsulasi percobaan, dan membuang degradasi saya aplikasi untuk kebocoran sumber daya karena kesalahan manusia daripada secara otomatis ditangani oleh gc.
Apa keputusan desain bahasa yang menyebabkan bahasa-bahasa ini tidak memiliki cara untuk mengeksekusi logika kustom pada pembuangan objek? Saya harus membayangkan ada alasan bagus. Saya ingin lebih memahami keputusan teknis dan teoritis yang mengakibatkan bahasa-bahasa ini tidak memiliki dukungan untuk penghancuran / finalisasi objek.
Memperbarui:
Mungkin cara yang lebih baik untuk mengungkapkan pertanyaan saya:
Mengapa bahasa memiliki konsep bawaan objek contoh dengan kelas atau struktur seperti kelas bersama dengan instantiasi khusus (konstruktor), namun sepenuhnya menghilangkan fungsionalitas penghancuran / penyelesaian? 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. Namun sebagian besar bahasa itu tidak mendukungnya.
Saya tidak berpikir itu adalah kasus di mana destruktor mungkin tidak pernah dipanggil, karena itu akan menjadi kebocoran memori inti, yang dirancang untuk menghindari gcs. Saya bisa melihat argumen yang mungkin adalah bahwa destructor / finalizer mungkin tidak dipanggil sampai beberapa waktu di masa depan, tetapi itu tidak menghentikan Java atau Python dari mendukung fungsi.
Apa alasan desain inti bahasa untuk tidak mendukung segala bentuk finalisasi objek?
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.Jawaban:
Pola yang Anda bicarakan, di mana objek tahu cara membersihkan sumber daya mereka, jatuh ke dalam tiga kategori yang relevan. Mari kita tidak mengacaukan destruktor dengan finalizer - hanya satu yang terkait dengan pengumpulan sampah:
The Pola finalizer : metode pembersihan dinyatakan secara otomatis, didefinisikan oleh programmer, yang disebut secara otomatis.
Finalizers dipanggil secara otomatis sebelum deallokasi oleh seorang pemulung. Istilah ini berlaku jika algoritma pengumpulan sampah yang digunakan dapat menentukan siklus hidup objek.
The pola destructor : metode pembersihan dinyatakan secara otomatis, didefinisikan oleh programmer, yang disebut secara otomatis hanya kadang-kadang.
Destructors dapat dipanggil secara otomatis untuk objek yang dialokasikan stack (karena umur objek adalah deterministik), tetapi harus secara eksplisit dipanggil pada semua jalur eksekusi yang mungkin untuk objek yang dialokasikan heap (karena masa objek tidak bersifat deterministik).
The Pola Pemelihara : metode pembersihan menyatakan, didefinisikan, dan disebut oleh programmer.
Pemrogram membuat metode pembuangan dan menyebutnya sendiri - ini adalah tempat
myObject.destroy()
metode kustom Anda jatuh. Jika pembuangan mutlak diperlukan, maka pelempar harus dipanggil pada semua jalur eksekusi yang memungkinkan.Finalizer adalah droid yang Anda cari.
Pola finalizer (pola yang ditanyakan oleh pertanyaan Anda) adalah mekanisme untuk mengaitkan objek dengan sumber daya sistem (soket, deskriptor file, dll.) Untuk saling direklamasi oleh pengumpul sampah. Tetapi, para finalizer pada dasarnya bergantung pada algoritma pengumpulan sampah yang digunakan.
Pertimbangkan asumsi Anda ini:
Salah secara teknis (terima kasih, @babou). Pengumpulan sampah pada dasarnya adalah tentang ingatan, bukan benda. Jika atau ketika suatu algoritma pengumpulan menyadari memori suatu objek tidak lagi digunakan tergantung pada algoritma dan (mungkin) bagaimana objek Anda merujuk satu sama lain. Mari kita bicara tentang dua jenis pengumpul sampah runtime. Ada banyak cara untuk mengubah dan menambah ini ke teknik dasar:
Menelusuri GC. Ini jejak memori, bukan benda. Kecuali jika ditambah untuk melakukannya, mereka tidak mempertahankan kembali referensi ke objek dari memori. Kecuali jika ditambah, GC ini tidak akan tahu kapan suatu objek dapat diselesaikan, bahkan jika mereka tahu kapan memorinya tidak dapat dijangkau. Oleh karena itu, panggilan finalizer tidak dijamin.
Referensi Menghitung GC . Ini menggunakan objek untuk melacak memori. Mereka memodelkan jangkauan objek dengan grafik referensi yang diarahkan. Jika ada siklus dalam grafik referensi objek Anda, maka semua objek dalam siklus tidak akan pernah memanggil finalizer mereka (sampai penghentian program, jelas). Sekali lagi, panggilan finalizer tidak dijamin.
TLDR
Pengumpulan sampah sulit dan beragam. Panggilan finalizer tidak dapat dijamin sebelum penghentian program.
sumber
finalize()
menyebabkan objek dibersihkan untuk direferensikan lagi?). Namun, tidak dapat menjamin finalizer dipanggil sebelum penghentian program tidak menghentikan Java untuk mendukungnya. Tidak mengatakan jawaban Anda salah, mungkin saja tidak lengkap. Masih posting yang sangat bagus. Terima kasih.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 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):
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.
sumber
getting memory recycled
, yang saya panggilreclamation
, dan melakukan beberapa pembersihan sebelum itu, seperti reklamasi sumber daya lain atau memperbarui beberapa tabel objek, yang saya sebutfinalization
. Bagi saya ini adalah masalah yang relevan, tetapi saya mungkin telah melewatkan satu poin dalam terminologi Anda, yang baru bagi saya.Pola destruktor objek sangat mendasar untuk penanganan kesalahan dalam pemrograman sistem, tetapi tidak ada hubungannya dengan pengumpulan sampah. Sebaliknya, itu ada hubungannya dengan pencocokan objek seumur hidup ke ruang lingkup, dan dapat diimplementasikan / digunakan dalam bahasa apa pun yang memiliki fungsi kelas satu.
Contoh (pseudocode). Misalkan Anda memiliki tipe "file mentah", seperti jenis deskriptor file Posix. Ada empat operasi dasar,
open()
,close()
,read()
,write()
. Anda ingin menerapkan tipe file "aman" yang selalu dibersihkan sendiri. (Yaitu, yang memiliki konstruktor dan penghancur otomatis.)Saya akan menganggap bahasa kami memiliki penanganan perkecualian
throw
,try
danfinally
(dalam bahasa tanpa penanganan perkecualian, Anda dapat mengatur disiplin di mana pengguna tipe Anda mengembalikan nilai khusus untuk menunjukkan kesalahan.)Anda mengatur fungsi yang menerima fungsi yang berfungsi. Fungsi pekerja menerima satu argumen (pegangan ke file "aman").
Anda juga menyediakan implementasi dari
read()
danwrite()
untuksafe_file
(yang hanya memanggilraw_file
read()
danwrite()
). Sekarang pengguna menggunakansafe_file
tipe seperti ini:Sebuah destruktor C ++ benar-benar hanya gula sintaksis untuk satu
try-finally
blok. Hampir semua yang saya lakukan di sini adalah mengonversi apa yangsafe_file
akan dikompilasi menjadi kelas C ++ dengan konstruktor dan destruktor. Perhatikan bahwa C ++ tidak memilikifinally
pengecualian, khususnya karena Stroustrup merasa bahwa menggunakan destruktor eksplisit lebih baik secara sintaksis (dan ia memperkenalkannya ke dalam bahasa sebelum bahasa tersebut memiliki fungsi anonim).(Ini adalah penyederhanaan dari salah satu cara orang telah melakukan penanganan kesalahan dalam bahasa seperti Lisp selama bertahun-tahun. Saya pikir saya pertama kali bertemu dengannya di akhir 1980-an atau awal 1990-an, tapi saya tidak ingat di mana.)
sumber
safe_file
danwith_file_opened_for_read
(objek yang menutup sendiri ketika keluar dari ruang lingkup ). Itu yang penting, bahwa itu tidak memiliki sintaks yang sama dengan konstruktor tidak relevan. Lisp, Skema, Java, Scala, Go, Haskell, Rust, Javascript, Clojure semuanya mendukung fungsi-fungsi kelas satu yang cukup, sehingga mereka tidak memerlukan destruktor untuk menyediakan fitur berguna yang sama.Ini bukan jawaban penuh untuk pertanyaan itu, tetapi saya ingin menambahkan beberapa pengamatan yang belum tercakup dalam jawaban atau komentar lainnya.
Pertanyaan secara implisit mengasumsikan bahwa kita sedang berbicara tentang bahasa berorientasi objek gaya Simula, yang dengan sendirinya membatasi. Dalam kebanyakan bahasa, bahkan mereka yang memiliki objek, tidak semuanya adalah objek. Mesin untuk menerapkan destruktor akan membebankan biaya yang tidak semua pelaksana bahasa mau membayar.
C ++ memiliki beberapa jaminan implisit tentang perintah penghancuran. Jika Anda memiliki struktur data seperti pohon, misalnya, anak-anak akan dihancurkan sebelum orang tua. Ini bukan kasus dalam bahasa GC'd, jadi sumber daya hierarkis dapat dirilis dalam urutan yang tidak terduga. Untuk sumber daya non-memori, ini bisa penting.
sumber
Ketika dua kerangka kerja GC yang paling populer (Java dan .NET) sedang dirancang, saya pikir para penulis berharap bahwa finalisasi akan bekerja dengan cukup baik untuk menghindari kebutuhan akan bentuk-bentuk pengelolaan sumber daya lainnya. Banyak aspek desain bahasa dan kerangka kerja dapat sangat disederhanakan jika tidak perlu semua fitur yang diperlukan untuk mengakomodasi 100% manajemen sumber daya yang andal dan deterministik. Dalam C ++, penting untuk membedakan antara konsep:
Pointer / referensi yang mengidentifikasi objek yang secara eksklusif dimiliki oleh pemegang referensi, dan yang tidak diidentifikasi oleh pointer / referensi yang tidak diketahui pemiliknya.
Pointer / referensi yang mengidentifikasi objek yang dapat dibagi yang tidak secara eksklusif dimiliki oleh siapa pun.
Pointer / referensi yang mengidentifikasi objek yang secara eksklusif dimiliki oleh pemegang referensi, tetapi yang dapat diakses melalui "pandangan" pemilik tidak memiliki cara untuk melacak.
Pointer / referensi yang mengidentifikasi objek yang menyediakan tampilan objek yang dimiliki oleh orang lain.
Jika bahasa / kerangka kerja GC tidak perlu khawatir tentang manajemen sumber daya, semua hal di atas dapat diganti dengan satu jenis referensi.
Saya akan menemukan ide naif bahwa finalisasi akan menghilangkan kebutuhan untuk bentuk-bentuk lain dari manajemen sumber daya, tetapi apakah harapan seperti itu masuk akal atau tidak pada saat itu, sejarah telah menunjukkan bahwa ada banyak kasus yang membutuhkan manajemen sumber daya yang lebih tepat daripada penyelesaian menyediakan . Saya kebetulan berpikir bahwa penghargaan mengakui kepemilikan pada tingkat bahasa / kerangka kerja akan cukup untuk membenarkan biaya (kompleksitas harus ada di suatu tempat, dan memindahkannya ke bahasa / kerangka kerja akan menyederhanakan kode pengguna) tetapi mengakui bahwa ada signifikansi manfaat desain untuk memiliki satu "jenis" referensi - sesuatu yang hanya bekerja jika bahasa / kerangka kerja agnostik dengan masalah pembersihan sumber daya.
sumber
Destructor dalam C ++ sebenarnya menggabungkan dua hal . Ini membebaskan RAM dan membebaskan id sumber daya.
Bahasa lain memisahkan masalah ini dengan membuat GC bertanggung jawab membebaskan RAM sementara fitur bahasa lain bertanggung jawab membebaskan id sumber daya.
Itu semua tentang GC. Mereka hanya melakukan satu hal dan itu untuk memastikan Anda tidak kehabisan memori. Jika RAM tidak terbatas, semua GC akan pensiun karena tidak ada lagi alasan nyata bagi mereka untuk ada.
Bahasa dapat menyediakan berbagai cara untuk membebaskan id sumber daya dengan:
manual
.CloseOrDispose()
tersebar di seluruh kodemanual
.CloseOrDispose()
tersebar di "finally
blok " manualmanual "blok id sumber daya" (yaitu
using
,with
,try
-dengan-sumber daya , dll) yang mengotomatiskan.CloseOrDispose()
setelah blok tersebut dilakukandijamin "blok id sumber daya" yang terotomatisasi
.CloseOrDispose()
setelah blok selesaiBanyak bahasa menggunakan mekanisme manual (yang bertentangan dengan jaminan) yang menciptakan peluang untuk pengelolaan sumber daya yang salah. Ambil kode NodeJS sederhana ini:
..di mana programmer lupa untuk menutup file yang dibuka.
Selama program terus berjalan, file yang dibuka akan terjebak dalam limbo. Ini mudah diverifikasi dengan mencoba membuka file menggunakan HxD dan memverifikasi bahwa itu tidak dapat dilakukan:
Membebaskan id sumber daya di dalam destruktor C ++ juga tidak dijamin. Anda mungkin berpikir RAII beroperasi seperti "blok id sumber daya" yang dijamin, namun tidak seperti "blok id sumber daya", bahasa C ++ tidak menghentikan objek yang menyediakan blok RAII agar tidak bocor , sehingga blok RAII mungkin tidak pernah dilakukan .
Karena mereka mengelola id sumber daya menggunakan cara lain, seperti yang disebutkan di atas.
Karena mereka mengelola id sumber daya menggunakan cara lain, seperti yang disebutkan di atas.
Karena mereka mengelola id sumber daya menggunakan cara lain, seperti yang disebutkan di atas.
Java tidak memiliki destruktor.
Dokumen Java menyebutkan :
..tapi menempatkan kode manajemen resource-id di dalam
Object.finalizer
sebagian besar dianggap sebagai anti-pola ( lih .). Kode-kode itu seharusnya ditulis di situs panggilan.Untuk orang-orang yang menggunakan anti-pola, pembenaran mereka adalah bahwa mereka mungkin lupa untuk melepaskan id sumber daya di situs panggilan. Dengan demikian, mereka melakukannya lagi di finalizer, untuk berjaga-jaga.
Tidak ada banyak kasus penggunaan untuk finalizer karena mereka menjalankan sepotong kode antara waktu ketika tidak ada lagi referensi kuat ke objek, dan waktu ketika memori itu direklamasi oleh GC.
Case use yang mungkin adalah ketika Anda ingin menyimpan catatan waktu antara objek yang dikumpulkan oleh GC dan waktu ketika tidak ada lagi referensi kuat ke objek, seperti:
sumber
menemukan referensi tentang hal ini di Dr Dobbs wrt c ++ yang memiliki gagasan yang lebih umum yang berpendapat destructor bermasalah dalam bahasa di mana mereka diterapkan. ide yang kasar di sini tampaknya adalah bahwa tujuan utama dari destructor adalah untuk menangani deallokasi memori, dan itu sulit dicapai dengan benar. memori dialokasikan sedikit demi sedikit tetapi objek yang berbeda terhubung dan kemudian tanggung jawab / alokasi deallokasi tidak begitu jelas.
jadi solusi untuk ini dari seorang pengumpul sampah berevolusi tahun yang lalu, tetapi pengumpulan sampah tidak didasarkan pada objek yang menghilang dari ruang lingkup pada metode keluar (itu adalah ide konseptual yang sulit untuk diterapkan), tetapi pada pengumpul yang berjalan secara berkala, agak tidak deterministik, ketika aplikasi mengalami "tekanan memori" (yaitu kehabisan memori).
dengan kata lain konsep manusia semata-mata tentang "objek yang baru tidak digunakan" sebenarnya dalam beberapa hal adalah abstraksi menyesatkan dalam arti bahwa tidak ada objek yang "instan" menjadi tidak terpakai. objek yang tidak terpakai hanya dapat "ditemukan" dengan menjalankan algoritma pengumpulan sampah yang melintasi grafik referensi objek dan algoritma berkinerja terbaik berjalan sebentar-sebentar.
mungkin saja algoritma pengumpulan sampah yang lebih baik menunggu untuk ditemukan yang dapat secara instan mengidentifikasi objek yang tidak digunakan, yang kemudian dapat mengarah pada kode panggilan destruktor yang konsisten, tetapi orang belum ditemukan setelah bertahun-tahun penelitian di daerah tersebut.
solusi untuk area manajemen sumber daya seperti file atau koneksi tampaknya memiliki objek "manajer" yang berupaya menangani penggunaannya.
sumber