Saya perlu tahu kapan finalize()
metode ini dipanggil dalam JVM
. Saya membuat kelas uji yang menulis ke file ketika finalize()
metode ini dipanggil dengan menimpanya. Itu tidak dieksekusi. Adakah yang bisa memberi tahu saya alasan mengapa tidak dijalankan?
330
finalize()
dan pengumpulan sampah tidak berdampak apa-apa.Jawaban:
Secara umum yang terbaik adalah tidak bergantung
finalize()
untuk melakukan pembersihan dll.Menurut Javadoc (yang layak dibaca), itu adalah:
Seperti yang Joachim tunjukkan, ini mungkin tidak pernah terjadi dalam kehidupan suatu program jika objek selalu dapat diakses.
Juga, pemulung tidak dijamin berjalan pada waktu tertentu. Secara umum, apa yang saya coba katakan adalah
finalize()
mungkin bukan metode terbaik untuk digunakan secara umum kecuali ada sesuatu yang spesifik yang Anda butuhkan.sumber
finalize
akan bermanfaat?finalize()
metode pada untuk kelas utama dipanggil ketika sebuah >> instance << kelas adalah sampah yang dikumpulkan, tidak ketika metode Menghentikan utama. Dan selain itu, kelas utama bisa menjadi sampah yang dikumpulkan sebelum aplikasi selesai; misalnya dalam aplikasi multi-utas tempat utas "utama" membuat utas lain dan kemudian kembali. (Dalam prakteknya, classloader non-standar akan diperlukan ....)The
finalize
metode ini disebut ketika suatu objek adalah untuk mendapatkan sampah yang dikumpulkan. Itu bisa kapan saja setelah memenuhi syarat untuk pengumpulan sampah.Perhatikan bahwa sangat mungkin bahwa suatu objek tidak pernah mengumpulkan sampah (dan karenanya
finalize
tidak pernah disebut). Ini bisa terjadi ketika objek tidak pernah memenuhi syarat untuk gc (karena itu dapat dicapai sepanjang masa JVM) atau ketika tidak ada pengumpulan sampah yang benar-benar berjalan antara waktu objek menjadi memenuhi syarat dan waktu JVM berhenti berjalan (ini sering terjadi dengan sederhana program uji).Ada beberapa cara untuk memberitahu JVM agar berjalan
finalize
pada objek yang belum dipanggil, tetapi menggunakannya juga bukan ide yang baik (jaminan metode itu juga tidak terlalu kuat).Jika Anda mengandalkan
finalize
operasi aplikasi yang benar, maka Anda melakukan sesuatu yang salah.finalize
seharusnya hanya digunakan untuk pembersihan sumber daya (biasanya non-Jawa). Dan itu justru karena JVM tidak menjamin yangfinalize
pernah dipanggil pada objek apa pun.sumber
Closable
antarmuka (dan ide di baliknya) mungkin yang Anda inginkan:.close()
tutup / buang sumber daya dan minta pengguna kelas Anda untuk memanggilnya pada waktu yang tepat. Anda mungkin ingin menambahkanfinalize
metode "hanya untuk menyelamatkan", tetapi itu akan lebih sebagai alat debugging daripada perbaikan yang sebenarnya (karena itu tidak cukup dapat diandalkan).System.gc()
untuk memanggil FileInputStream :: finalize (), maka saya bisa memindahkan file.dikutip dari: http://www.janeg.ca/scjp/gc/finalize.html
Anda juga dapat memeriksa artikel ini:
sumber
finalize()
Metode Java bukan destruktor dan tidak boleh digunakan untuk menangani logika yang bergantung pada aplikasi Anda. Java spec menyatakan tidak ada jaminan bahwafinalize
metode ini dipanggil sama sekali selama masa pakai aplikasi.Apa yang Anda inginkan adalah kombinasi
finally
dan metode pembersihan, seperti pada:sumber
Lihat Java Efektif, edisi 2 halaman 27. Butir 7: Hindari finalizer
Untuk mengakhiri sumber daya, gunakan coba-akhirnya sebagai gantinya:
sumber
Metode finalisasi akan dipanggil setelah GC mendeteksi bahwa objek tidak lagi dapat dijangkau, dan sebelum benar-benar mendapatkan kembali memori yang digunakan oleh objek.
Jika suatu objek tidak pernah menjadi tidak terjangkau,
finalize()
tidak akan pernah dipanggil.Jika GC tidak berjalan maka
finalize()
mungkin tidak pernah dipanggil. (Biasanya, GC hanya berjalan ketika JVM memutuskan bahwa ada kemungkinan cukup banyak sampah untuk membuatnya berharga.)Diperlukan lebih dari satu siklus GC sebelum GC menentukan bahwa objek tertentu tidak dapat dijangkau. (Java GC biasanya merupakan kolektor "generasi" ...)
Setelah GC mendeteksi suatu objek tidak dapat dijangkau dan dapat diselesaikan, ia ditempatkan pada antrian finalisasi. Finalisasi biasanya terjadi secara tidak sinkron dengan GC normal.
(Spesifikasi JVM sebenarnya memungkinkan JVM untuk tidak pernah menjalankan finalizers ... asalkan tidak mengklaim kembali ruang yang digunakan oleh objek. JVM yang diimplementasikan dengan cara ini akan lumpuh / tidak berguna, tetapi jika perilaku ini "diizinkan" .)
Hasilnya adalah tidak bijaksana untuk mengandalkan finalisasi untuk melakukan hal-hal yang harus dilakukan dalam kerangka waktu yang pasti. Ini adalah "praktik terbaik" untuk tidak menggunakannya sama sekali. Seharusnya ada cara yang lebih baik (yaitu lebih dapat diandalkan) untuk melakukan apa pun yang Anda coba lakukan dalam
finalize()
metode ini.Satu-satunya penggunaan yang sah untuk finalisasi adalah untuk membersihkan sumber daya yang terkait dengan objek yang telah hilang oleh kode aplikasi. Bahkan kemudian, Anda harus mencoba untuk menulis kode aplikasi sehingga tidak kehilangan objek di tempat pertama. (Misalnya, gunakan Java 7+ coba-dengan-sumber daya untuk memastikan yang
close()
selalu disebut ...)Sulit dikatakan, tetapi ada beberapa kemungkinan:
sumber
Karena ada ketidakpastian dalam pemanggilan metode finalize () oleh JVM (tidak yakin apakah finalize () yang ditimpa akan dieksekusi atau tidak), untuk tujuan penelitian, cara yang lebih baik untuk mengamati apa yang terjadi ketika finalize () dipanggil, adalah dengan memaksa JVM untuk memanggil pengumpulan sampah dengan perintah
System.gc()
.Secara khusus, finalize () dipanggil ketika suatu objek tidak lagi digunakan. Tetapi ketika kita mencoba menyebutnya dengan membuat objek baru, tidak ada kepastian panggilannya. Jadi untuk kepastian kita membuat
null
objekc
yang jelas tidak memiliki penggunaan di masa depan, maka kita melihatc
panggilan final objek.Contoh
Keluaran
Catatan - Bahkan setelah mencetak hingga 70 dan setelah objek b yang tidak digunakan dalam program, ada ketidakpastian bahwa b dihapus atau tidak oleh JVM karena "Metode penyelesaian terpanggil di kelas Bike ..." tidak dicetak.
sumber
System.gc();
bukanlah jaminan bahwa pengumpulan sampah akan benar-benar berjalan.Finalisasi akan mencetak hitungan untuk pembuatan kelas.
utama
Seperti yang Anda lihat. Put berikut menunjukkan gc dieksekusi pertama kali ketika jumlah kelas adalah 36.
sumber
Setelah bergulat dengan metode finalizer akhir-akhir ini (untuk membuang koneksi pool selama pengujian), saya harus mengatakan bahwa finalizer tidak memiliki banyak hal. Menggunakan VisualVM untuk mengamati serta menggunakan referensi yang lemah untuk melacak interaksi aktual saya menemukan bahwa hal-hal berikut ini benar dalam lingkungan Java 8 (Oracle JDK, Ubuntu 15):
Pemikiran Akhir
Metode finalisasi tidak dapat diandalkan tetapi hanya dapat digunakan untuk satu hal. Anda dapat memastikan bahwa suatu objek ditutup atau dibuang sebelum dikumpulkan dengan sampah sehingga memungkinkan untuk mengimplementasikan brankas yang gagal jika objek dengan siklus hidup yang lebih kompleks yang melibatkan tindakan akhir-hidup ditangani dengan benar. Itulah satu alasan yang dapat saya pikirkan yang membuatnya berharga untuk menimpanya.
sumber
Suatu Objek menjadi memenuhi syarat untuk pengumpulan Sampah atau GC jika tidak dapat dijangkau dari utas langsung apa pun atau refrensi statis dengan kata lain Anda dapat mengatakan bahwa suatu objek menjadi memenuhi syarat untuk pengumpulan sampah jika semua rujukannya nol. Ketergantungan siklik tidak dihitung sebagai referensi sehingga jika Objek A memiliki referensi objek B dan objek B memiliki referensi Obyek A dan mereka tidak memiliki referensi langsung lainnya maka kedua Objek A dan B akan memenuhi syarat untuk pengumpulan sampah. Secara umum suatu objek menjadi memenuhi syarat untuk pengumpulan sampah di Jawa pada kasus-kasus berikut:
sumber
final
bidang objek digunakan berulang kali selama perhitungan lambat, dan objek tidak akan pernah digunakan setelah itu, apakah objek akan tetap hidup sampai terakhir kode sumber meminta bidang, atau bisakah JIT menyalin bidang ke variabel sementara dan kemudian meninggalkan objek sebelum perhitungan?GC.KeepAlive()
fungsi yang tidak melakukan apa pun kecuali memaksa GC untuk menganggap bahwa itu mungkin menggunakan objek, tapi saya tahu tidak ada fungsi seperti itu di Jawa. Orang bisa menggunakanvolatile
variabel untuk tujuan itu, tetapi menggunakan variabel semata-mata untuk tujuan seperti itu akan tampak sia-sia.FinalizerReference
, sehingga tidak memerlukan siklus GC untuk mengetahui bahwa tidak ada referensi. Sinkronisasi sudah cukup untuk memastikan hubungan yang terjadi sebelum ; karena finalisasi mungkin (sebenarnya) berjalan di utas yang berbeda, seringkali itu memang perlu secara formal. Java 9 akan menambahkanReference.reachabilityFence
...Finalize
dipanggil sama sekali adalah jika JIT menghasilkan kode yang melakukannya secara langsung. Apakah kode sinkronisasi biasanya diharapkan untuk objek yang hanya diharapkan untuk digunakan dalam satu utas? Jika suatu objek melakukan beberapa tindakan yang perlu diurungkan sebelum ditinggalkan (mis. Membuka koneksi soket dan mendapatkan penggunaan eksklusif ke sumber daya di ujung lainnya), memiliki finalizer menutup koneksi saat kode masih menggunakan soket akan menjadi bencana . Apakah normal jika kode menggunakan sinkronisasi ...metode finalisasi tidak dijamin. Metode ini dipanggil ketika objek menjadi memenuhi syarat untuk GC. Ada banyak situasi di mana objek mungkin bukan sampah yang dikumpulkan.
sumber
Terkadang ketika dihancurkan, suatu objek harus melakukan suatu tindakan. Misalnya, jika suatu objek memiliki sumber daya non-java seperti file handle atau font, Anda dapat memverifikasi bahwa sumber daya ini dilepaskan sebelum menghancurkan suatu objek. Untuk mengelola situasi seperti itu, java menawarkan mekanisme yang disebut "menyelesaikan". Dengan menyelesaikannya, Anda dapat menentukan tindakan spesifik yang terjadi ketika suatu objek akan dihapus dari pengumpul sampah. Untuk menambahkan finalizer ke kelas cukup tentukan metode finalize () . Waktu eksekusi Java memanggil metode ini setiap kali akan menghapus objek dari kelas itu. Dalam metode finalisasi ()Anda menentukan tindakan yang harus dilakukan sebelum menghancurkan objek. Pengumpul sampah secara berkala mencari objek yang tidak lagi merujuk ke status apa pun yang berjalan atau secara tidak langsung objek lain dengan referensi. Sebelum aset dilepaskan, Java runtime memanggil metode finalize () pada objek. Metode finalize () memiliki bentuk umum berikut:
Dengan kata kunci yang dilindungi , akses untuk menyelesaikan () dengan kode di luar kelasnya dicegah. Penting untuk dipahami bahwa finalize () dipanggil sesaat sebelum pengumpulan sampah. Ini tidak dipanggil ketika suatu objek meninggalkan ruang lingkup, misalnya. Itu berarti Anda tidak bisa tahu kapan, atau jika, menyelesaikan () akan dieksekusi. Akibatnya, program harus menyediakan cara lain untuk membebaskan sumber daya sistem atau sumber daya lain yang digunakan oleh objek. Anda seharusnya tidak mengandalkan finalisasi () untuk menjalankan program secara normal.
sumber
Kelas tempat kita menimpa metode finalisasi
Peluang metode penyelesaian dipanggil
ketika memori kelebihan beban dengan objek dump, gc akan memanggil metode finalisasi
jalankan dan lihat konsol, di mana Anda tidak menemukan metode finalisasi sering dipanggil, ketika memori menjadi kelebihan maka metode finalisasi akan dipanggil.
sumber
Sumber
sumber
finalize()
disebut sesaat sebelum pengumpulan sampah. Itu tidak dipanggil ketika suatu objek keluar dari ruang lingkup. Ini berarti Anda tidak bisa tahu kapan atau bahkan apakahfinalize()
akan dieksekusi.Contoh:
Jika program Anda berakhir sebelum pemulung terjadi, maka
finalize()
tidak akan dijalankan. Oleh karena itu, itu harus digunakan sebagai prosedur cadangan untuk memastikan penanganan sumber daya lain yang tepat, atau untuk aplikasi penggunaan khusus, bukan sebagai cara yang digunakan program Anda dalam operasi normalnya.sumber
Seperti ditunjukkan dalam https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers ,
sumber
Coba jalankan Program ini untuk pemahaman yang lebih baik
sumber