Apakah ada destruktor untuk Java?

594

Apakah ada destruktor untuk Java? Sepertinya saya tidak dapat menemukan dokumentasi tentang ini. Jika tidak ada, bagaimana saya bisa mendapatkan efek yang sama?

Untuk membuat pertanyaan saya lebih spesifik, saya menulis sebuah aplikasi yang berkaitan dengan data dan spesifikasinya mengatakan bahwa harus ada tombol 'reset' yang membawa aplikasi kembali ke keadaan semula yang baru diluncurkan. Namun, semua data harus 'hidup' kecuali jika aplikasi ditutup atau tombol reset ditekan.

Menjadi biasanya seorang programmer C / C ++, saya pikir ini akan sepele untuk diimplementasikan. (Dan karenanya saya berencana untuk mengimplementasikannya paling akhir.) Saya menyusun program saya sedemikian rupa sehingga semua objek yang 'dapat-reset' berada di kelas yang sama sehingga saya dapat menghancurkan semua objek 'hidup' ketika tombol reset ditekan.

Saya berpikir jika yang saya lakukan hanyalah merapikan data dan menunggu pengumpul sampah mengumpulkannya, bukankah akan ada kebocoran memori jika pengguna saya berulang kali memasukkan data dan menekan tombol reset? Saya juga berpikir karena Jawa cukup matang sebagai bahasa, harus ada cara untuk mencegah hal ini terjadi atau menangani masalah ini dengan anggun.

wai
sumber
7
Hanya ada kebocoran memori jika Anda memegang referensi ke objek yang tidak Anda butuhkan. yaitu Ada bug dalam program Anda. GC akan berjalan sesuai kebutuhan (kadang-kadang lebih cepat)
Peter Lawrey
17
Mesin virtual tidak akan menjalankan GC segera jika Anda memproses data dengan cepat melalui objek. Gagasan bahwa GC selalu dapat mengikuti, atau membuat keputusan yang tepat adalah kekeliruan.
Kieveli
1
@Kieveli Bukankah JVM menjalankan GC sebelum memberikan kesalahan?
WVrock
4
Ya, alangkah baiknya jika ada destructor untuk Java yang akan menghancurkannya sekali untuk semua.
Tomáš Zato - Reinstate Monica

Jawaban:

526

Karena Java adalah bahasa sampah yang dikumpulkan, Anda tidak dapat memprediksi kapan (atau bahkan jika) suatu objek akan dihancurkan. Karenanya tidak ada padanan langsung dari destruktor.

Ada metode warisan yang disebut finalize, tetapi ini disebut sepenuhnya atas kebijakan pengumpul sampah. Jadi untuk kelas yang perlu merapikan secara eksplisit, konvensi adalah untuk mendefinisikan metode tutup dan hanya menggunakan penyelesaian untuk pemeriksaan kewarasan (yaitu jika dekat belum dipanggil lakukan sekarang dan catat kesalahan).

Ada pertanyaan yang melahirkan diskusi mendalam tentang penyelesaian baru-baru ini, sehingga harus memberikan lebih mendalam jika diperlukan ...

Garth Gilmour
sumber
5
Apakah "close ()" dalam konteks ini merujuk ke metode di java.lang.Autocloseable?
Sridhar Sarnobat
21
Tidak, AutoCloseable diperkenalkan di Java 7 tetapi konvensi 'close ()' telah ada lebih lama.
Jon Onstott
mengapa Anda tidak dapat memprediksi kapan (atau bahkan jika) suatu objek akan dihancurkan. apa perkiraan cara lain untuk memprediksi itu?
dctremblay
Penghancuran objek @dctremblay dilakukan oleh pengumpul sampah dan pengumpul sampah mungkin tidak pernah berjalan seumur hidup aplikasi.
Piro mengatakan Reinstate Monica
4
Perhatikan bahwa finalizemetode ini sudah tidak digunakan lagi di Jawa 9.
Lii
124

Lihatlah pernyataan coba-dengan-sumber daya . Sebagai contoh:

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  System.out.println(br.readLine());
} catch (Exception e) {
  ...
} finally {
  ...
}

Di sini sumber daya yang tidak lagi dibutuhkan dibebaskan dalam BufferedReader.close()metode. Anda dapat membuat kelas Anda sendiri yang mengimplementasikan AutoCloseabledan menggunakannya dengan cara yang serupa.

Pernyataan ini lebih terbatas daripada finalizedalam hal penataan kode, tetapi pada saat yang sama membuat kode lebih mudah untuk dipahami dan dipelihara. Juga, tidak ada jaminan bahwa suatu finalizemetode dipanggil sama sekali selama masa pakai aplikasi.

Vitalii Fedorenko
sumber
12
Saya terkejut ini memiliki sedikit suara. Itu adalah jawaban yang sebenarnya.
nurettin
20
Saya tidak setuju bahwa itu adalah jawaban yang sebenarnya. Jika sebuah instance memiliki sumber daya yang ditangani selama periode waktu yang lebih besar, melintasi beberapa panggilan metode, maka try-with-resources tidak akan membantu. Kecuali tidak apa-apa untuk menutup dan membuka kembali sumber daya pada tingkat mengatakan metode dipanggil - bukan fakta umum.
Eric
14
Memang, ini bukan jawaban yang sebenarnya. Tidak mungkin untuk menggunakan struktur ini untuk mengelola penghancuran suatu objek kecuali jika konstruksi dan penggunaan objek sepenuhnya dienkapsulasi oleh trydan finallydigunakan untuk memaksa panggilan obj.finalize(). Dan bahkan pengaturan ini tidak menyelesaikan masalah yang ditimbulkan oleh OP: penghancuran objek pada pertengahan program yang dipicu oleh tombol "reset".
7yl4r
1
Pengguna lain telah menunjukkan ini dilakukan di titik masuk aplikasi Anda. Tentukan variabel Anda secara global. Inisialisasi dalam fungsi entri, dengan coba. Deinitialize pada akhirnya (ketika aplikasi Anda ditutup). Itu sepenuhnya mungkin.
TamusJRoyce
1
@nurettin Java 7 baru keluar selama 3 bulan ketika pertanyaan diajukan, jika itu membantu membuatnya lebih masuk akal.
corsiKa
110

Tidak, tidak ada destruktor di sini. Alasannya adalah bahwa semua objek Java dialokasikan tumpukan dan sampah dikumpulkan. Tanpa deallokasi eksplisit (yaitu operator penghapusan C ++) tidak ada cara yang masuk akal untuk mengimplementasikan destruktor nyata.

Java mendukung finalizer, tetapi mereka dimaksudkan untuk digunakan hanya sebagai pengamanan untuk objek yang memegang pegangan ke sumber daya asli seperti soket, pegangan file, pegangan jendela, dll. Ketika pengumpul sampah mengumpulkan objek tanpa finalizer, ia hanya menandai memori wilayah bebas dan hanya itu. Ketika objek memiliki finalizer, pertama-tama disalin ke lokasi sementara (ingat, kami mengumpulkan sampah di sini), kemudian enqueued menjadi antrian yang menunggu untuk diselesaikan dan kemudian benang Finalizer memilah antrian dengan prioritas sangat rendah dan menjalankan finalizer.

Ketika aplikasi keluar, JVM berhenti tanpa menunggu objek yang tertunda diselesaikan, sehingga praktis tidak ada jaminan bahwa finalizer Anda akan pernah berjalan.

ddimitrov
sumber
4
Terima kasih telah menyebutkan sumber daya asli - ini adalah salah satu area di mana metode "seperti destruktor" berguna.
Nathan Osman
ya, saya menghadapi masalah yang sama sekarang dengan membebaskan sumber daya / pegangan yang dialokasikan melalui panggilan asli ke C ++.
nikk
@ddimitrov, secara teori bisa java menerapkan deallocation eksplisit? Atau ini kontradiksi yang logis?
mil
1
@mils secara naif menerapkan deallokasi eksplisit akan mematahkan asumsi Java bahwa referensi menunjuk ke objek langsung. Anda dapat mengulangi semua petunjuk dan menghapus alias, tapi itu lebih mahal daripada GC. Atau Anda dapat mencoba menggunakan beberapa sistem tipe linear (lihat "kepemilikan" pada Rust), tetapi itu adalah perubahan bahasa utama. Ada opsi lain juga (lihat memori lingkup JavaRT, dll), tetapi secara umum deallokasi eksplisit tidak cocok dengan bahasa Java.
ddimitrov
31

Penggunaan metode finalisasi () harus dihindari. Mereka bukan mekanisme yang dapat diandalkan untuk pembersihan sumber daya dan dimungkinkan untuk menyebabkan masalah dalam pengumpul sampah dengan menyalahgunakan mereka.

Jika Anda memerlukan panggilan deallokasi di objek Anda, katakan untuk melepaskan sumber daya, gunakan panggilan metode eksplisit. Konvensi ini dapat dilihat di API yang ada (mis. Closeable , Graphics.dispose () , Widget.dispose () ) dan biasanya dipanggil via try / akhirnya.

Resource r = new Resource();
try {
    //work
} finally {
    r.dispose();
}

Upaya untuk menggunakan objek yang dibuang harus membuang pengecualian runtime (lihat IllegalStateException ).


EDIT:

Saya berpikir, jika yang saya lakukan hanyalah merapikan data dan menunggu pengumpul sampah mengumpulkannya, bukankah akan ada kebocoran memori jika pengguna saya berulang kali memasukkan data dan menekan tombol reset?

Secara umum, semua yang perlu Anda lakukan adalah referensi objek - setidaknya, ini adalah cara yang seharusnya bekerja. Jika Anda khawatir tentang pengumpulan sampah, periksa Java SE 6 HotSpot [tm] Tuning Pengumpulan Sampah Mesin Virtual (atau dokumen yang setara untuk versi JVM Anda).

McDowell
sumber
1
Bukan itu yang dimaksud dereference. Ini bukan "mengatur referensi terakhir dari sebuah objek ke nol" melainkan mendapatkan (membaca) nilai dari referensi sehingga Anda dapat menggunakannya untuk operasi selanjutnya.
1
Apakah coba .. akhirnya masih merupakan pendekatan yang valid dan direkomendasikan? Misalkan, saya sebelumnya memanggil metode asli dalam finalize (), dapatkah saya memindahkan panggilan ke klausa akhirnya? class Resource { finalize() { destroy(); } protected native void destroy(); } class Alt_Resource { try (Resource r = new Resource()) { // use r } finalize { r.destroy(); }
aashima
r tidak akan dicakup ke blok akhirnya. Karena itu, Anda tidak dapat menyebut menghancurkan pada saat itu. Sekarang, jika Anda memperbaiki ruang lingkup untuk membuat objek sebelum blok coba, Anda akan berakhir dengan kasus "sebelum mencoba-dengan-sumber daya" yang jelek.
userAsh
21

Dengan Java 1.7 dirilis, Anda sekarang memiliki opsi tambahan untuk menggunakan try-with-resourcesblok. Sebagai contoh,

public class Closeable implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("closing..."); 
    }
    public static void main(String[] args) {
        try (Closeable c = new Closeable()) {
            System.out.println("trying..."); 
            throw new Exception("throwing..."); 
        }
        catch (Exception e) {
            System.out.println("catching..."); 
        }
        finally {
            System.out.println("finalizing..."); 
        } 
    }
}

Jika Anda menjalankan kelas ini, c.close() akan dieksekusi ketika tryblok dibiarkan, dan sebelum catchdan finallyblok dieksekusi. Berbeda dengan dalam hal finalize()metode, close()dijamin akan dieksekusi. Namun, tidak perlu mengeksekusi secara eksplisit dalam finallyklausa.

waku
sumber
bagaimana jika kita tidak menggunakan blok coba-dengan-sumber daya? Saya pikir kita dapat memanggil close in finalize () hanya untuk memastikan bahwa close telah dipanggil.
shintoZ
3
@shintoZ ketika saya membaca jawaban di atas tidak ada jaminan finalize()eksekusi
Asif Mushtaq
14

Saya sepenuhnya setuju dengan jawaban lain, mengatakan tidak bergantung pada eksekusi penyelesaian.

Selain blok coba-tangkap-akhirnya, Anda dapat menggunakan Runtime # addShutdownHook (diperkenalkan di Java 1.3) untuk melakukan pembersihan akhir dalam program Anda.

Itu tidak sama dengan destruktor , tetapi orang mungkin menerapkan hook shutdown yang memiliki objek pendengar terdaftar yang metode pembersihan (tutup koneksi database persisten, hapus kunci file, dan sebagainya) dapat dipanggil - hal-hal yang biasanya dilakukan di penghancur . Sekali lagi - ini bukan pengganti destruktor tetapi dalam beberapa kasus, Anda dapat mendekati fungsionalitas yang diinginkan dengan ini.

Keuntungan dari ini adalah memiliki perilaku dekonstruksi yang longgar digabungkan dari sisa program Anda.

Markus
sumber
addShutdownHook tampaknya diperkenalkan di Java 1.3. Bagaimanapun, ini tersedia untuk saya dalam 1,5. :) Lihat ini: stackoverflow.com/questions/727151/…
skiphoppy
1
FYI, menurut pengalaman saya, shutdown hooks tidak akan dipanggil jika Anda menggunakan tombol merah "terminate" di Eclipse - seluruh JVM dihancurkan segera, hook shutdown tidak disebut dengan anggun. Berarti Anda mungkin melihat perilaku yang berbeda selama pengembangan dan produksi jika Anda berkembang menggunakan eclipse
Hamy
11

Tidak, java.lang.Object#finalizeadalah yang terdekat yang bisa Anda dapatkan.

Namun, kapan (dan jika) itu disebut, tidak dijamin.
Lihat:java.lang.Runtime#runFinalizersOnExit(boolean)

menebal
sumber
5
Metode yang mungkin atau mungkin tidak dipanggil pada dasarnya tidak berguna dalam buku saya. Lebih baik tidak mencemari bahasa dengan metode khusus yang tidak berguna yang paling tidak memberikan rasa aman yang salah. Saya tidak akan pernah mengerti mengapa pengembang bahasa Jawa berpikir menyelesaikan adalah ide yang bagus.
antred
@antred Para pengembang bahasa Jawa setuju . Saya kira, saat itu, untuk beberapa dari mereka, itu adalah pertama kalinya mereka merancang bahasa pemrograman dan lingkungan runtime dengan pengumpulan sampah. Apa yang kurang dimengerti adalah mengapa bahasa yang dikelola lainnya menyalin konsep itu pada suatu waktu, ketika sudah dipahami bahwa konsep ini adalah ide yang buruk.
Holger
7

Pertama, perhatikan bahwa karena Jawa adalah pengumpulan sampah, jarang perlu melakukan apa pun tentang penghancuran objek. Pertama karena Anda biasanya tidak memiliki sumber daya yang dikelola untuk dibebaskan, dan kedua karena Anda tidak dapat memprediksi kapan atau jika itu akan terjadi, jadi tidak pantas untuk hal-hal yang perlu Anda lakukan "segera setelah tidak ada yang menggunakan objek saya lagi ".

Anda dapat diberi tahu setelah objek dihancurkan menggunakan java.lang.ref.PhantomReference (sebenarnya, mengatakan itu telah dihancurkan mungkin sedikit tidak akurat, tetapi jika referensi hantu untuk itu di-antri maka itu tidak lagi dapat dipulihkan, yang biasanya berjumlah hal yang sama). Penggunaan umum adalah:

  • Pisahkan sumber daya di kelas Anda yang perlu dirusak menjadi objek pembantu lain (perhatikan bahwa jika semua yang Anda lakukan adalah menutup koneksi, yang merupakan kasus umum, Anda tidak perlu menulis kelas baru: koneksi yang akan ditutup akan menjadi "objek pembantu" dalam kasus itu).
  • Saat Anda membuat objek utama, buat juga PhantomReference untuknya. Entah ini merujuk ke objek helper baru, atau mengatur peta dari objek PhantomReference ke objek helper yang sesuai.
  • Setelah objek utama dikumpulkan, PhantomReference di-antri (atau lebih tepatnya mungkin di-antri - seperti finalizer, tidak ada jaminan hal itu akan terjadi, misalnya jika VM keluar maka tidak akan menunggu). Pastikan Anda sedang memproses antriannya (baik di utas khusus atau dari waktu ke waktu). Karena referensi keras ke objek helper, objek helper belum dikumpulkan. Jadi lakukan pembersihan apa pun yang Anda suka pada objek helper, lalu buang PhantomReference dan helper pada akhirnya akan dikumpulkan juga.

Ada juga finalize (), yang terlihat seperti destruktor tetapi tidak berperilaku seperti itu. Ini biasanya bukan pilihan yang baik.

Steve Jessop
sumber
Mengapa PhantomReference bukannya WeakReference?
uckelman
2
@uckelman: jika semua yang Anda inginkan adalah notifikasi, maka PhantomReference melakukan tugasnya, ini dirancang untuk itu. Semantik tambahan WeakReference tidak diperlukan di sini, dan pada titik di mana ReferenceQueue Anda diberitahukan, Anda tidak dapat lagi memulihkan objek melalui WeakReference, jadi satu-satunya alasan untuk menggunakannya adalah untuk menyelamatkan karena harus mengingat bahwa PhantomReference ada. Pekerjaan ekstra apa pun yang dilakukan WeakReference mungkin dapat diabaikan, tetapi mengapa repot-repot dengan itu?
Steve Jessop
Terima kasih telah mengisyaratkan PhantomReference. Itu tidak sempurna, tetapi masih lebih baik daripada tidak sama sekali.
foo
@SteveJessop “kerja ekstra” apa, menurut Anda, memiliki referensi yang lemah dibandingkan dengan referensi hantu?
Holger
6

Itu finalize() fungsi destruktor.

Namun, seharusnya tidak digunakan secara normal karena dipanggil setelah GC dan Anda tidak bisa tahu kapan itu akan terjadi (jika pernah).

Selain itu, dibutuhkan lebih dari satu GC untuk mendelokasi objek yang dimiliki finalize() .

Anda harus mencoba untuk membersihkan tempat-tempat logis dalam kode Anda menggunakan try{...} finally{...}pernyataan!

Shimi Bandiel
sumber
5

Saya setuju dengan sebagian besar jawabannya.

Anda tidak harus bergantung sepenuhnya pada salah satu finalizeatauShutdownHook

menyelesaikan

  1. JVM tidak menjamin kapan finalize()metode ini akan dipanggil.

  2. finalize()dipanggil hanya sekali oleh utas GC. Jika suatu objek pulih dari metode penyelesaian, maka finalizetidak akan dipanggil lagi.

  3. Dalam aplikasi Anda, Anda mungkin memiliki beberapa objek hidup, tempat pengumpulan sampah tidak pernah dipanggil.

  4. Apa pun Exceptionyang dilemparkan dengan metode finalisasi diabaikan oleh utas GC

  5. System.runFinalization(true)dan Runtime.getRuntime().runFinalization(true)metode meningkatkan kemungkinan finalize()metode pemanggilan tetapi sekarang kedua metode ini telah usang. Metode ini sangat berbahaya karena kurangnya keamanan benang dan kemungkinan pembuatan jalan buntu.

shutdownHooks

public void addShutdownHook(Thread hook)

Mendaftarkan hook shutdown mesin virtual baru.

Mesin virtual Java dimatikan sebagai respons terhadap dua jenis peristiwa:

  1. Program keluar secara normal, ketika utas non-daemon terakhir keluar atau ketika metode keluar (ekuivalen System.exit) dipanggil, atau
  2. Mesin virtual diakhiri sebagai respons terhadap interupsi pengguna, seperti mengetikkan ^ C, atau peristiwa di seluruh sistem, seperti logoff pengguna atau shutdown sistem.
  3. Kait penonaktifan hanyalah utas yang diinisialisasi tetapi tidak dimulai. Ketika mesin virtual memulai urutan penonaktifannya, mesin virtual akan memulai semua kait penonaktifan terdaftar dalam urutan yang tidak ditentukan dan membiarkannya berjalan secara bersamaan. Setelah semua kait selesai, maka akan menjalankan semua finalizer tanpa diundang jika finalisasi saat keluar telah diaktifkan.
  4. Akhirnya, mesin virtual akan berhenti. Perhatikan bahwa thread daemon akan terus berjalan selama urutan shutdown, seperti halnya thread non-daemon jika shutdown dimulai dengan memanggil metode keluar.
  5. Kait mati juga harus menyelesaikan pekerjaan mereka dengan cepat. Ketika sebuah program memanggil keluar harapan adalah bahwa mesin virtual akan segera dimatikan dan keluar.

    Tetapi bahkan dokumentasi Oracle mengutipnya

Dalam keadaan yang jarang terjadi, mesin virtual dapat dibatalkan, yaitu, berhenti berjalan tanpa mematikan dengan bersih

Ini terjadi ketika mesin virtual diakhiri secara eksternal, misalnya dengan SIGKILLsinyal pada Unix atau TerminateProcesspanggilan pada Microsoft Windows. Mesin virtual juga dapat dibatalkan jika metode asli berjalan salah dengan, misalnya, merusak struktur data internal atau mencoba mengakses memori yang tidak ada. Jika mesin virtual batal, maka tidak ada jaminan yang dapat dibuat tentang apakah ada shutdown hooks yang akan dijalankan.

Kesimpulan : gunakan try{} catch{} finally{}blok dengan tepat dan lepaskan sumber daya penting dalam finally(}blok. Selama pelepasan sumber daya di finally{}blok, tangkap Exceptiondan Throwable.

Ravindra babu
sumber
4

Jika hanya ingatan yang Anda khawatirkan, jangan. Hanya percaya pada GC itu melakukan pekerjaan yang layak. Saya benar-benar melihat sesuatu tentang hal itu menjadi sangat efisien sehingga bisa lebih baik untuk kinerja untuk membuat banyak objek kecil daripada menggunakan array besar dalam beberapa kasus.

John Nilsson
sumber
3

Mungkin Anda bisa menggunakan percobaan ... akhirnya memblokir untuk menyelesaikan objek dalam aliran kontrol di mana Anda menggunakan objek. Tentu saja itu tidak terjadi secara otomatis, tetapi tidak juga kerusakan di C ++. Anda sering melihat penutupan sumber daya di blok akhirnya.

SAYA MEMBERIKAN JAWABAN KAMU
sumber
1
Ini adalah jawaban yang tepat ketika sumber daya tersebut memiliki satu pemilik dan tidak pernah memiliki referensi untuk itu "dicuri" oleh kode lain.
Steve Jessop
3

Ada anotasi @Cleanup di Lombok yang sebagian besar menyerupai penghancur C ++:

@Cleanup
ResourceClass resource = new ResourceClass();

Saat memprosesnya (pada waktu kompilasi), Lombok menyisipkan try-finallyblok yang sesuai sehingga resource.close()dipanggil, ketika eksekusi meninggalkan ruang lingkup variabel. Anda juga dapat menentukan secara eksplisit metode lain untuk melepaskan sumber daya, misalnya resource.dispose():

@Cleanup("dispose")
ResourceClass resource = new ResourceClass();
Alexey
sumber
2
Keuntungan yang saya lihat adalah bahwa akan ada lebih sedikit sarang (Yang mungkin signifikan jika Anda memiliki banyak objek yang memerlukan "penghancuran").
Alexey
Blok coba-dengan-sumber daya dapat memiliki banyak sumber daya dalam satu kesempatan
Alexander - Reinstate Monica
1
Tetapi tidak ada instruksi di antara mereka.
Alexey
Adil. Saya kira maka rekomendasinya adalah untuk memilih coba-dengan-sumber daya, bahkan untuk banyak sumber daya, kecuali jika perlu ada instruksi di antara mereka yang memaksa Anda untuk membuat blok coba-dengan-sumber daya baru (meningkatkan sarang), kemudian gunakan@Cleanup
Alexander - Reinstate Monica
2

Setara terdekat dengan destruktor di Jawa adalah metode finalize () . Perbedaan besar pada destruktor tradisional adalah Anda tidak dapat memastikan kapan akan dipanggil, karena itu adalah tanggung jawab pengumpul sampah. Saya sangat merekomendasikan membaca ini dengan cermat sebelum menggunakannya, karena pola RAIA khas Anda untuk menangani file dan seterusnya tidak akan bekerja dengan baik dengan finalize ().

Nik
sumber
2

Banyak jawaban bagus di sini, tetapi ada beberapa informasi tambahan tentang mengapa Anda harus menghindari menggunakan finalize () .

Jika JVM keluar karena System.exit()atau Runtime.getRuntime().exit(), finalizers tidak akan dijalankan secara default. Dari Javadoc untuk Runtime.exit () :

Urutan shutdown mesin virtual terdiri dari dua fase. Pada fase pertama semua kait shutdown terdaftar, jika ada, dimulai dalam beberapa urutan yang tidak ditentukan dan dibiarkan berjalan secara bersamaan sampai selesai. Pada fase kedua semua finalis yang tidak diikutsertakan dijalankan jika finalisasi saat keluar telah diaktifkan. Setelah ini dilakukan, mesin virtual berhenti.

Anda dapat menelepon System.runFinalization()tetapi itu hanya membuat "upaya terbaik untuk menyelesaikan semua finalisasi yang beredar" - bukan jaminan.

Ada sebuah System.runFinalizersOnExit()metode, tetapi jangan menggunakannya - itu tidak aman, sudah usang sejak lama.

kaan
sumber
1

Jika Anda menulis Java Applet, Anda dapat mengganti metode Applet "destroy ()". Ini...

 * Called by the browser or applet viewer to inform
 * this applet that it is being reclaimed and that it should destroy
 * any resources that it has allocated. The stop() method
 * will always be called before destroy().

Jelas bukan yang Anda inginkan, tetapi mungkin apa yang dicari orang lain.


sumber
1

Hanya memikirkan pertanyaan asli ... yang, saya pikir kita dapat menyimpulkan dari semua jawaban yang dipelajari lainnya, dan juga dari Jawa Efektif yang penting dari Bloch , butir 7, "Hindari finalizer", mencari solusi untuk pertanyaan yang sah dengan cara yang tidak pantas untuk bahasa Jawa ...:

... bukankah solusi yang cukup jelas untuk melakukan apa yang sebenarnya diinginkan OP adalah menjaga semua objek Anda yang perlu diatur ulang dalam semacam "playpen", yang semua objek non-reset memiliki referensi hanya melalui semacam objek accessor ...

Dan kemudian ketika Anda perlu "mengatur ulang" Anda lepaskan playpen yang ada dan buat yang baru: semua web objek di playpen dilemparkan terpaut, tidak pernah kembali, dan suatu hari akan dikumpulkan oleh GC.

Jika salah satu dari objek ini adalah Closeable(atau tidak, tetapi memiliki closemetode), Anda dapat meletakkannya di Bagdalam playpen saat dibuat (dan mungkin dibuka), dan tindakan terakhir dari pengakses sebelum memotong playpen adalah pergi melalui semua Closeablespenutupan mereka ...?

Kode mungkin akan terlihat seperti ini:

accessor.getPlaypen().closeCloseables();
accessor.setPlaypen( new Playpen() );

closeCloseablesmungkin akan menjadi metode pemblokiran, mungkin melibatkan kait (misalnya CountdownLatch), untuk berurusan dengan (dan menunggu sesuai kebutuhan) setiap Runnables/ Callablesdi setiap utas yang spesifik untuk Playpendiakhiri sebagaimana mestinya, khususnya di utas JavaFX.

mike rodent
sumber
0

Meskipun ada banyak kemajuan dalam teknologi GC Java, Anda masih perlu memperhatikan referensi Anda. Banyak kasus pola referensi yang tampaknya sepele yang sebenarnya adalah sarang tikus di bawah tenda.

Dari posting Anda itu tidak terdengar seperti Anda mencoba menerapkan metode reset untuk tujuan penggunaan kembali objek (benar?). Apakah objek Anda memegang sumber daya jenis apa pun yang perlu dibersihkan (yaitu, aliran yang harus ditutup, benda yang dikumpulkan atau dipinjam yang harus dikembalikan)? Jika satu-satunya hal yang Anda khawatirkan adalah memori dealloc maka saya akan mempertimbangkan kembali struktur objek saya dan mencoba untuk memverifikasi bahwa objek saya adalah struktur mandiri yang akan dibersihkan pada waktu GC.

tyler
sumber
0

Tidak ada kelas destruktor persis di Jawa, kelas dihancurkan di java secara otomatis oleh pengumpul sampah. tetapi Anda bisa melakukannya menggunakan di bawah satu tetapi itu tidak persis sama:

menyelesaikan()

Ada pertanyaan yang melontarkan diskusi mendalam tentang finalisasi , sehingga Anda harus mendapatkan lebih mendalam jika diminta ...

Manas
sumber
0

Tidak ada Java tidak memiliki destruktor. Alasan utama di baliknya di Jawa adalah Pengumpul Sampah yang secara pasif selalu bekerja di latar belakang dan semua objek dibuat dalam memori tumpukan, itu adalah tempat di mana GC bekerja. Di c ++ di sana kami harus secara eksplisit memanggil fungsi hapus karena tidak ada pengumpul sampah seperti itu.

Anubhav Mishra
sumber
-3

Saya biasanya berurusan dengan C ++ dan itulah yang membawa saya ke pencarian destructor juga. Saya banyak menggunakan JAWA sekarang. Apa yang saya lakukan, dan itu mungkin bukan kasus terbaik untuk semua orang, tapi saya menerapkan destruktor saya sendiri dengan mengatur ulang semua nilai ke 0 atau di sana default melalui fungsi.

Contoh:

public myDestructor() {

variableA = 0; //INT
variableB = 0.0; //DOUBLE & FLOAT
variableC = "NO NAME ENTERED"; //TEXT & STRING
variableD = false; //BOOL

}

Idealnya ini tidak akan bekerja untuk semua situasi, tetapi di mana ada variabel global itu akan berfungsi selama Anda tidak memiliki banyak dari mereka.

Saya tahu saya bukan programmer Java terbaik, tetapi tampaknya bekerja untuk saya.

ChristianGLong
sumber
Cobalah untuk menggunakan benda yang lebih abadi, setelah Anda 'mengerti' semuanya akan lebih masuk akal :)
R. van Twisk
5
Ini tidak begitu salah karena tidak ada gunanya - yaitu tidak mencapai apa-apa. Jika program Anda mengharuskan jenis mentah diatur ulang agar berfungsi dengan benar, maka instance kelas Anda memiliki cakupan yang salah, artinya Anda mungkin menetapkan ulang properti objek yang ada ke properti objek baru, tanpa membuat Obyek baru ().
simo.3792
1
Kecuali bahwa ada banyak kebutuhan untuk mengatur ulang variabel. Saya memilih destruktor nama karena cocok dengan apa yang saya lakukan. Itu mencapai sesuatu, hanya tidak ada yang Anda mengerti
ChristianGLong