Kapan metode finalize () dipanggil di Java?


330

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?


34
Sama seperti catatan tambahan: finalisasi ditandai sebagai usang di Jawa 9
Reg


jika ada yang memiliki referensi ke objek Anda atau bahkan kelas. finalize()dan pengumpulan sampah tidak berdampak apa-apa.
ha9u63ar

Jawaban:


273

Secara umum yang terbaik adalah tidak bergantung finalize()untuk melakukan pembersihan dll.

Menurut Javadoc (yang layak dibaca), itu adalah:

Dipanggil oleh pengumpul sampah pada objek ketika pengumpulan sampah menentukan bahwa tidak ada lagi referensi ke objek.

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.


19
Dengan kata lain (hanya untuk memperjelas pembaca masa depan) itu tidak pernah dipanggil pada kelas utama, karena, ketika kelas utama ditutup, tidak ada sampah yang perlu dikumpulkan. OS membersihkan semua aplikasi yang digunakan.
Mark Jeronimus

113
"bukan metode terbaik untuk digunakan ... kecuali ada sesuatu yang spesifik yang Anda butuhkan untuk" - eh, kalimat itu berlaku untuk 100% dari segalanya, jadi tidak membantu. Jawaban Joachim Sauer jauh lebih baik
BT

1
@ Zom-B contoh Anda sangat membantu untuk klarifikasi, tetapi hanya untuk menjadi bertele-tele, mungkin itu bisa dipanggil pada kelas utama jika kelas utama membuat utas non-daemon dan kemudian kembali?
Tom G

3
Jadi apa situasi di mana finalizeakan bermanfaat?
nbro

3
@ MarkJeronimus - Sebenarnya, itu tidak relevan. The 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 ....)
Stephen C

379

The finalizemetode 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 finalizetidak 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 finalizepada objek yang belum dipanggil, tetapi menggunakannya juga bukan ide yang baik (jaminan metode itu juga tidak terlalu kuat).

Jika Anda mengandalkan finalizeoperasi aplikasi yang benar, maka Anda melakukan sesuatu yang salah. finalizeseharusnya hanya digunakan untuk pembersihan sumber daya (biasanya non-Jawa). Dan itu justru karena JVM tidak menjamin yang finalizepernah dipanggil pada objek apa pun.


2
@Rajesh. Tidak. Ini bukan masalah "masa hidup". Anda dapat meletakkan program Anda dalam loop tanpa batas (selama bertahun-tahun), dan jika pengumpul sampah tidak diperlukan, program tidak akan pernah berjalan.
ChrisCantrell

5
@VikasVerma: pengganti yang sempurna bukanlah apa-apa: Anda tidak perlu membutuhkannya. Satu-satunya kasus di mana masuk akal adalah jika kelas Anda mengelola beberapa sumber daya eksternal (seperti koneksi TCP / IP, file ... apa pun yang tidak dapat ditangani oleh Java GC). Dalam kasus tersebut Closableantarmuka (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 menambahkan finalizemetode "hanya untuk menyelamatkan", tetapi itu akan lebih sebagai alat debugging daripada perbaikan yang sebenarnya (karena itu tidak cukup dapat diandalkan).
Joachim Sauer

4
@Dragonborn: itu sebenarnya pertanyaan yang sangat berbeda dan harus ditanyakan secara terpisah. Ada kait shutdown, tetapi mereka tidak dijamin jika JVM mati tiba-tiba (alias macet). Tetapi jaminan mereka secara signifikan lebih kuat daripada jaminan bagi para finalis (dan mereka juga lebih aman).
Joachim Sauer

4
Paragraf terakhir Anda mengatakan untuk menggunakannya hanya untuk membersihkan sumber daya meskipun tidak ada jaminan akan pernah dipanggil. Apakah optimisme ini berbicara? Saya akan berasumsi bahwa sesuatu yang tidak dapat diandalkan karena ini juga tidak cocok untuk membersihkan sumber daya.
Jeroen Vannevel

2
Finalizers kadang-kadang dapat menyelamatkan hari ... Saya punya kasus di mana perpustakaan pihak ke-3 menggunakan FileInputStream, tidak pernah menutupnya. Kode saya memanggil kode perpustakaan, dan kemudian mencoba untuk memindahkan file, gagal karena masih terbuka. Saya harus memaksa panggilan System.gc()untuk memanggil FileInputStream :: finalize (), maka saya bisa memindahkan file.
Elist

73
protected void finalize() throws Throwable {}
  • setiap kelas mewarisi finalize()metode dari java.lang.Object
  • metode ini dipanggil oleh pengumpul sampah ketika tidak ada lagi referensi ke objek yang ada
  • Metode finalisasi objek tidak melakukan tindakan tetapi mungkin ditimpa oleh kelas apa pun
  • biasanya itu harus diganti untuk membersihkan sumber daya non-Java yaitu menutup file
  • jika mengganti finalize()itu adalah praktik pemrograman yang baik untuk menggunakan pernyataan try-catch-akhirnya dan untuk selalu menelepon super.finalize(). Ini adalah tindakan pengamanan untuk memastikan Anda tidak secara tidak sengaja melewatkan penutupan sumber daya yang digunakan oleh objek yang memanggil kelas

    protected void finalize() throws Throwable {
         try {
             close();        // close open files
         } finally {
             super.finalize();
         }
     }
  • setiap pengecualian yang dilemparkan oleh finalize()selama pengumpulan sampah menghentikan finalisasi tetapi sebaliknya diabaikan

  • finalize() tidak pernah berjalan lebih dari sekali pada objek apa pun

dikutip dari: http://www.janeg.ca/scjp/gc/finalize.html

Anda juga dapat memeriksa artikel ini:


25
Artikel JavaWorld yang Anda tautkan adalah dari tahun 1998, dan memiliki beberapa saran menarik, khususnya saran yang memanggil System.runFinalizersOnExit () untuk memastikan finalizer berjalan sebelum JVM keluar. Metode itu saat ini sudah tidak digunakan lagi, dengan komentar 'Metode ini pada dasarnya tidak aman. Hal ini dapat mengakibatkan finalizer dipanggil pada objek hidup sementara utas lainnya secara bersamaan memanipulasi objek-objek tersebut, menghasilkan perilaku yang tidak menentu atau kebuntuan. ' Jadi saya tidak akan melakukan itu.
Greg Chabala

3
Karena runFinalizerOnExit () BUKAN thread-safe, apa yang bisa dilakukan adalah Runtime.getRuntime (). AddShutdownHook (Thread baru () {public void run () {destrMyEnclosingClass ();}}); dalam konstruktor Kelas.
Ustaman Sangat

2
@Ustaman Sangat Itu cara untuk melakukannya, tapi ingat ini menetapkan referensi ke instance Anda dari shutdownHook, yang cukup banyak menjamin bahwa kelas Anda tidak pernah sampah dikumpulkan. Dengan kata lain, ini adalah kebocoran memori.
pieroxy

1
@pieroxy, sementara saya setuju semua orang di sini tentang tidak menggunakan finalize () untuk apa pun, saya tidak melihat mengapa harus ada referensi dari hook shutdown. Orang bisa memiliki referensi lunak.
Ustaman Sangat

25

finalize()Metode Java bukan destruktor dan tidak boleh digunakan untuk menangani logika yang bergantung pada aplikasi Anda. Java spec menyatakan tidak ada jaminan bahwa finalizemetode ini dipanggil sama sekali selama masa pakai aplikasi.

Apa yang Anda inginkan adalah kombinasi finallydan metode pembersihan, seperti pada:

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {

    if (null != myObj) {
        myObj.cleanup();
    }
}

20

Lihat Java Efektif, edisi 2 halaman 27. Butir 7: Hindari finalizer

Finalizers tidak dapat diprediksi, seringkali berbahaya, dan umumnya tidak perlu. tidak pernah melakukan sesuatu yang kritis terhadap waktu dalam finalizer. tidak pernah bergantung pada finalizer untuk memperbarui keadaan gigih kritis.

Untuk mengakhiri sumber daya, gunakan coba-akhirnya sebagai gantinya:

// try-finally block guarantees execution of termination method
Foo foo = new Foo(...);
try {
    // Do what must be done with foo
    ...
} finally {
    foo.terminate(); // Explicit termination method
}

3
atau gunakan coba-dengan-sumber daya
Gabriel Garcia

3
Ini mengasumsikan masa hidup objek berada dalam lingkup satu fungsi. Yang, tentu saja, bukan kasus yang dirujuk OP, juga bukan kasus yang dibutuhkan siapa pun. Pikirkan "jumlah referensi pengembalian mesin cache". Anda ingin membebaskan entri cache ketika ref terakhir dibebaskan, tetapi Anda tidak tahu kapan ref terakhir dibebaskan. finalize () dapat mengurangi jumlah referensi, misalnya ... tetapi jika Anda meminta pengguna Anda untuk secara eksplisit memanggil fungsi bebas, Anda meminta kebocoran memori. biasanya saya hanya melakukan keduanya (fungsi rilis + periksa dua kali dalam penyelesaian ...) ...
Erik Aronesty

16

Kapan finalize()metode dipanggil di Jawa?

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 ...)


Saya membuat kelas uji yang menulis ke file ketika metode finalize () dipanggil dengan menimpanya. Itu tidak dieksekusi. Adakah yang bisa memberi tahu saya alasan mengapa tidak dijalankan?

Sulit dikatakan, tetapi ada beberapa kemungkinan:

  • Benda tersebut bukan sampah yang dikumpulkan karena masih bisa dijangkau.
  • Objeknya bukan sampah yang dikumpulkan karena GC tidak berjalan sebelum tes Anda selesai.
  • Objek ditemukan oleh GC dan ditempatkan dalam antrian finalisasi oleh GC, tetapi finalisasi tidak selesai sebelum tes Anda selesai.

10

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 nullobjek cyang jelas tidak memiliki penggunaan di masa depan, maka kita melihat cpanggilan final objek.

Contoh

class Car {

    int maxspeed;

    Car() {
        maxspeed = 70;
    }

    protected void finalize() {

    // Originally finalize method does nothing, but here we override finalize() saying it to print some stmt
    // Calling of finalize is uncertain. Difficult to observe so we force JVM to call it by System.gc(); GarbageCollection

        System.out.println("Called finalize method in class Car...");
    }
}

class Bike {

    int maxspeed;

    Bike() {
        maxspeed = 50;
    }

    protected void finalize() {
        System.out.println("Called finalize method in class Bike...");
    }
}

class Example {

    public static void main(String args[]) {
        Car c = new Car();
        c = null;    // if c weren`t null JVM wouldn't be certain it's cleared or not, null means has no future use or no longer in use hence clears it
        Bike b = new Bike();
        System.gc();    // should clear c, but not b
        for (b.maxspeed = 1; b.maxspeed <= 70; b.maxspeed++) {
            System.out.print("\t" + b.maxspeed);
            if (b.maxspeed > 50) {
                System.out.println("Over Speed. Pls slow down.");
            }
        }
    }
}

Keluaran

    Called finalize method in class Car...
            1       2       3       4       5       6       7       8       9
    10      11      12      13      14      15      16      17      18      19
    20      21      22      23      24      25      26      27      28      29
    30      31      32      33      34      35      36      37      38      39
    40      41      42      43      44      45      46      47      48      49
    50      51Over Speed. Pls slow down.
            52Over Speed. Pls slow down.
            53Over Speed. Pls slow down.
            54Over Speed. Pls slow down.
            55Over Speed. Pls slow down.
            56Over Speed. Pls slow down.
            57Over Speed. Pls slow down.
            58Over Speed. Pls slow down. 
            59Over Speed. Pls slow down.
            60Over Speed. Pls slow down.
            61Over Speed. Pls slow down.
            62Over Speed. Pls slow down.
            63Over Speed. Pls slow down.
            64Over Speed. Pls slow down.
            65Over Speed. Pls slow down.
            66Over Speed. Pls slow down.
            67Over Speed. Pls slow down.
            68Over Speed. Pls slow down.
            69Over Speed. Pls slow down.
            70Over Speed. Pls slow down.

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.


10
Menelepon System.gc();bukanlah jaminan bahwa pengumpulan sampah akan benar-benar berjalan.
Simon Forsberg

3
Juga tidak dijamin koleksi seperti apa yang akan dijalankan. Relevan karena sebagian besar GC Jawa adalah kolektor "generasi".
Stephen C

5

Finalisasi akan mencetak hitungan untuk pembuatan kelas.

protected void finalize() throws Throwable {
    System.out.println("Run F" );
    if ( checkedOut)
        System.out.println("Error: Checked out");
        System.out.println("Class Create Count: " + classCreate);
}

utama

while ( true) {
    Book novel=new Book(true);
    //System.out.println(novel.checkedOut);
    //Runtime.getRuntime().runFinalization();
    novel.checkIn();
    new Book(true);
    //System.runFinalization();
    System.gc();

Seperti yang Anda lihat. Put berikut menunjukkan gc dieksekusi pertama kali ketika jumlah kelas adalah 36.

C:\javaCode\firstClass>java TerminationCondition
Run F
Error: Checked out
Class Create Count: 36
Run F
Error: Checked out
Class Create Count: 48
Run F

4

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):

  • Finalisasi tidak segera disebut Finalizer (bagian GC) secara individual memiliki referensi secara sukarela
  • Pengumpul Sampah default mengumpulkan objek yang tidak dapat dijangkau
  • Finalisasi dipanggil secara massal dengan menunjuk pada detail implementasi bahwa ada fase tertentu pengumpul sampah membebaskan sumber dayanya.
  • Calling System.gc () sering tidak menghasilkan objek yang difinalisasi lebih sering, itu hanya menghasilkan Finalizer yang menyadari objek yang tidak dapat dijangkau lebih cepat
  • Menciptakan thread dump hampir selalu menghasilkan pemicu finalizer karena overhead heap yang tinggi selama melakukan heap dump atau mekanisme internal lainnya
  • Lapisan finalisasi terikat oleh persyaratan memori (membebaskan lebih banyak memori) atau dengan daftar objek yang ditandai untuk finalisasi yang tumbuh dari batas internal tertentu. Jadi, jika Anda memiliki banyak objek yang diselesaikan, fase finalisasi akan dipicu lebih sering dan lebih awal jika dibandingkan dengan hanya beberapa objek.
  • Ada beberapa keadaan yang System.gc () memicu penyelesaian secara langsung tetapi hanya jika rujukannya adalah kehidupan lokal dan pendek. Ini mungkin terkait generasi.

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.


2

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:

  1. Semua referensi dari objek itu secara eksplisit diatur ke nol misalnya objek = nol
  2. Objek dibuat di dalam blok dan referensi keluar lingkup setelah kontrol keluar dari blok itu.
  3. Objek induk diatur ke nol, jika suatu objek memegang referensi objek lain dan ketika Anda menetapkan referensi objek kontainer nol, anak atau objek yang terkandung secara otomatis menjadi memenuhi syarat untuk pengumpulan sampah.
  4. Jika suatu objek hanya memiliki referensi langsung melalui WeakHashMap, objek tersebut akan memenuhi syarat untuk pengumpulan sampah.

Jika finalbidang 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?
supercat

@supercat: pengoptimal dapat menulis ulang kode ke bentuk di mana objek tidak dibuat di tempat pertama; dalam kasus itu, mungkin diselesaikan setelah konstruktornya selesai, kecuali sinkronisasi memaksa urutan antara penggunaan objek dan finalizer.
Holger

@ Holger: Dalam kasus-kasus di mana JIT dapat melihat segala sesuatu yang akan terjadi pada suatu objek antara pembuatan dan pengabaiannya, saya tidak melihat alasan mengapa JIT menembakkan finalizer lebih awal. Pertanyaan sebenarnya adalah kode apa yang perlu dilakukan untuk memastikan bahwa finalizer tidak dapat diaktifkan dalam metode tertentu. Di. NET ada 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 menggunakan volatilevariabel untuk tujuan itu, tetapi menggunakan variabel semata-mata untuk tujuan seperti itu akan tampak sia-sia.
supercat

@ supercat: JIT tidak menjalankan finalisasi, itu hanya mengatur kode untuk tidak menyimpan referensi, meskipun, mungkin bermanfaat untuk secara langsung meminta 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 menambahkan Reference.reachabilityFence...
Holger

@ Holger: Jika JIT mengoptimalkan pembuatan objek, satu-satunya yang Finalizedipanggil 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 ...
supercat

2

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.


3
Salah. Apa yang Anda katakan adalah bahwa suatu objek diselesaikan ketika ia menjadi tidak terjangkau. Ini sebenarnya disebut ketika metode sebenarnya dikumpulkan.
Stephen C

2

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:

protected void finalize(){
    // This is where the finalization code is entered
}

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.


1

Kelas tempat kita menimpa metode finalisasi

public class TestClass {    
    public TestClass() {
        System.out.println("constructor");
    }

    public void display() {
        System.out.println("display");
    }
    @Override
    public void finalize() {
        System.out.println("destructor");
    }
}

Peluang metode penyelesaian dipanggil

public class TestGarbageCollection {
    public static void main(String[] args) {
        while (true) {
            TestClass s = new TestClass();
            s.display();
            System.gc();
        }
    }
}

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.


0

Java memungkinkan objek untuk mengimplementasikan metode yang disebut finalize () yang mungkin dipanggil.

metode finalize () dipanggil jika pengumpul sampah mencoba mengumpulkan objek.

Jika pemulung tidak berjalan, metode ini tidak dipanggil.

Jika pengumpul sampah gagal mengumpulkan objek dan mencoba menjalankannya lagi, metode ini tidak dipanggil untuk kedua kalinya.

Dalam praktiknya, Anda sangat tidak mungkin menggunakannya dalam proyek nyata.

Hanya perlu diingat bahwa itu mungkin tidak dipanggil dan pasti tidak akan dipanggil dua kali. Metode finalize () bisa berjalan nol atau satu kali.

Dalam kode berikut, metode finalize () tidak menghasilkan keluaran ketika kita menjalankannya sejak program keluar sebelum ada kebutuhan untuk menjalankan pengumpul sampah.

Sumber


0

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 apakah finalize()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.


0

Seperti ditunjukkan dalam https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers ,

Tidak ada waktu tetap di mana finalisator harus dieksekusi karena waktu eksekusi tergantung pada Java Virtual Machine (JVM). Satu-satunya jaminan adalah bahwa setiap metode finalizer yang dijalankan akan melakukannya beberapa saat setelah objek terkait menjadi tidak terjangkau (terdeteksi selama siklus pertama pengumpulan sampah) dan beberapa saat sebelum pengumpul sampah merebut kembali penyimpanan objek terkait (selama siklus kedua pengumpul sampah) . Eksekusi finalizer objek dapat ditunda untuk waktu yang lama secara sewenang-wenang setelah objek menjadi tidak terjangkau. Akibatnya, menjalankan fungsionalitas kritis-waktu seperti menutup file yang menangani dalam metode finalisasi (objek) bermasalah.


-3

Coba jalankan Program ini untuk pemahaman yang lebih baik

public class FinalizeTest 
{       
    static {
        System.out.println(Runtime.getRuntime().freeMemory());
    }

    public void run() {
        System.out.println("run");
        System.out.println(Runtime.getRuntime().freeMemory());
    }

     protected void finalize() throws Throwable { 
         System.out.println("finalize");
         while(true)
             break;          
     }

     public static void main(String[] args) {
            for (int i = 0 ; i < 500000 ; i++ ) {
                    new FinalizeTest().run();
            }
     }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.