Java'da finalize () yöntemi ne zaman çağrılır?


330

finalize()Yöntemin ne zaman çağrıldığını bilmem gerekiyor JVM. finalize()Yöntem geçersiz kılınarak çağrıldığında bir dosyaya yazan bir test sınıfı oluşturdum . Yürütülmez. Biri bana neden icra edilmediğini söyleyebilir mi?


34
Tıpkı bir yan not olarak: final, Java 9
Reg


nesnenizin veya sınıfın referansı varsa. finalize()ve çöp toplamanın herhangi bir etkisi yoktur.
ha9u63ar

Yanıtlar:


273

Genel olarak finalize()herhangi bir temizlik vb. Yapmaya güvenmemek en iyisidir .

Javadoc'a göre (okumaya değer olurdu), o:

Çöp toplama, nesneye daha fazla başvuru olmadığını belirlediğinde, bir nesne üzerindeki çöp toplayıcı tarafından çağrılır.

Joachim'in işaret ettiği gibi, nesneye her zaman erişilebilirse bu hiçbir zaman programın hayatında olamaz.

Ayrıca, çöp toplayıcının belirli bir zamanda çalışması garanti edilmez. Genel olarak, söylemeye çalıştığım finalize()şey, ihtiyacınız olan belirli bir şey olmadığı sürece genel olarak kullanmak için en iyi yöntem değil.


19
Başka bir deyişle (sadece gelecekteki okuyucular için açıklığa kavuşturmak için) ana sınıfta asla çağrılmaz, çünkü ana sınıf kapandığında çöp toplanmasına gerek yoktur. İşletim sistemi, uygulamanın kullandığı her şeyi temizler.
Mark Jeronimus

113
"Kullanmak için en iyi yöntem değil ... İhtiyacınız olan özel bir şey olmadığı sürece" - ah, bu cümle her şeyin% 100'ü için geçerlidir, bu yüzden yardımcı olmaz. Joachim Sauer'ın cevabı çok daha iyi
BT

1
@ Zom-B örneğiniz açıklama için yararlıdır, ancak sadece bilgiçlikçi olmak için, muhtemelen ana sınıf bir daemon olmayan iş parçacığı oluşturup sonra dönerse, ana sınıfta çağrılabilir mi?
Tom G

3
Peki finalizeyararlı olabilecek durumlar nelerdir?
nbro

3
@MarkJeronimus - Aslında bu alakasız. finalize()Sınıfının bir >> örneği << çöp değil, ana yöntem sona erer toplandığında ana sınıf için üzerinde yöntem çağrılır. Ayrıca, ana sınıf uygulama bitmeden önce toplanan çöp olabilir ; Örneğin, "ana" iş parçacığının başka iş parçacıkları oluşturduğu ve sonra geri döndüğü çok iş parçacıklı bir uygulamada (Uygulamada, standart olmayan bir sınıf yükleyici gerekli olacaktır ...)
Stephen C

379

Bu finalizeyöntem, bir nesne çöp toplanmak üzereyken çağrılır. Bu, çöp toplama için uygun hale geldikten sonra herhangi bir zamanda olabilir.

Bir nesnenin asla çöp toplanmamasının (ve dolayısıyla finalizeasla çağrılmamasının) tamamen mümkün olduğunu unutmayın . Bu, nesne asla gc için uygun olmazsa (JVM'nin tüm ömrü boyunca erişilebilir olduğu için) veya nesnenin uygun hale gelmesi ile JVM'nin çalışmayı durdurduğu zaman arasında hiçbir çöp toplama işlemi gerçekleşmediğinde ortaya çıkabilir (bu genellikle basit test programları).

JVM'ye finalizehenüz çağrılmadığı nesneler üzerinde çalışmasını söylemenin yolları vardır , ancak bunları kullanmak da iyi bir fikir değildir (bu yöntemin garantileri de çok güçlü değildir).

finalizeUygulamanızın doğru çalışmasına güveniyorsanız, yanlış bir şey yapıyorsunuz demektir. finalizegerektiğini , sadece (genellikle Java olmayan) kaynakların temizlik için kullanılabilir. Ve bu tam olarak JVM değil garanti yapar çünkü finalizeşimdiye kadar herhangi bir nesne üzerinde çağrılır.


2
@Rajesh. Hayır. Bu bir "yaşam süresi" sorunu değil. Programınızı sonsuz bir döngüye (yıllarca) koyabilirsiniz ve çöp toplayıcısına ihtiyaç duyulmazsa asla çalışmayacaktır.
ChrisCantrell

5
@VikasVerma: mükemmel değiştirme hiçbir şey değildir: onlara ihtiyacınız olmamalıdır. Mantıklı olması gereken tek durum, sınıfınızın bazı harici kaynakları (TCP / IP bağlantısı, dosya ... Java GC'nin işleyemediği herhangi bir şey) yönetip yönetmediğidir. Bu durumlarda Closablearabirim (ve arkasındaki fikir) muhtemelen istediğiniz şeydir: .close()kaynağı kapat / at ve sınıfınızın kullanıcısının doğru zamanda çağırmasını gerektirir. Sen belki bir eklemek istediğiniz finalizeyöntemi "yalnızca kaydet olmak" değil, (güvenilir yeterli değil çünkü) o gerçek bir düzeltme daha bir hata ayıklama aracı olacaktır.
Joachim Sauer

4
@Dragonborn: Bu aslında oldukça farklı bir soru ve ayrıca sorulması gerekiyor. Kapatma kancaları vardır, ancak JVM beklenmedik bir şekilde kapanırsa (aka çökmeler) garanti edilmez. Ancak garantileri, kesinleştiriciler için olanlardan önemli ölçüde daha güçlüdür (ve onlar da daha güvenlidir).
Joachim Sauer

4
Son paragrafınız, çağırılamayacağının garantisi olmasa bile, yalnızca kaynakları temizlemek için kullandığını söylüyor. Bu iyimserlik konuşuyor mu? Bu, kaynakların temizliği için de uygun olmayacağından, güvenilir olmayan bir şeyin olduğunu varsayacağım.
Jeroen Vannevel

2
Sonlandırıcılar bazen günü kurtarabilir ... 3. taraf bir kütüphanenin FileInputStream'i kullandığı, hiçbir zaman kapatmayan bir vakam vardı. Kodum kitaplığın kodunu çağırıyordu ve dosyayı hala açık olduğu için başarısız olarak taşımaya çalıştı. System.gc()FileInputStream :: finalize () çağırmak için çağrı zorlamak zorunda kaldı , sonra dosyayı taşıyabilir.
Elist

73
protected void finalize() throws Throwable {}
  • her sınıf finalize()yöntemi java.lang.Object kaynağından devralır
  • yöntem, nesneye artık başvuru kalmadığını belirlediğinde çöp toplayıcı tarafından çağrılır
  • Object finalize yöntemi hiçbir eylem gerçekleştirmez ancak herhangi bir sınıf tarafından geçersiz kılınabilir
  • normalde Java dışındaki kaynakları temizlemek yani bir dosyayı kapatmak geçersiz kılınmalıdır
  • geçersiz kılma durumunda finalize()bir try-catch-nihayet deyimi kullanmak ve her zaman aramak iyi bir programlama uygulamasıdır super.finalize(). Bu, sınıfı çağıran nesneler tarafından kullanılan bir kaynağı istemeden kapatmamanızı sağlayan bir güvenlik önlemidir.

    protected void finalize() throws Throwable {
         try {
             close();        // close open files
         } finally {
             super.finalize();
         }
     }
  • finalize()çöp toplama sırasında atılan herhangi bir istisna sonlandırmayı durdurur, ancak aksi halde yoksayılır

  • finalize() hiçbir zaman bir nesnede birden fazla çalıştırılmaz

alıntı yapılan: http://www.janeg.ca/scjp/gc/finalize.html

Bu makaleyi de kontrol edebilirsiniz:


25
Bağlandığınız JavaWorld makalesi 1998'den alınmıştır ve özellikle JVM çıkmadan önce sonlandırıcıların çalışmasını sağlamak için System.runFinalizersOnExit () yöntemini çağırmak gibi bazı ilginç önerilere sahiptir. Bu yöntem şu anda 'Bu yöntem doğal olarak güvensizdir. Diğer iş parçacıkları eşzamanlı olarak bu nesneleri manipüle ederken sonlandırıcıların canlı nesnelerde çağrılmasına neden olabilir ve bu da düzensiz davranışlara veya kilitlenmeye neden olabilir. ' Yani bunu yapmayacağım.
Greg Chabala

3
RunFinalizerOnExit () iş parçacığı için güvenli DEĞİLDİR, birinin yapabileceği şey Runtime.getRuntime (). AddShutdownHook (new Thread () {public void run () {destroyMyEnclosingClass ();}}); Sınıfın yapıcısında.
Ustaman Sangat

2
@Ustaman Sangat Bunu yapmanın bir yolu, ancak unutmayın ki bu, shutHook'tan örneğinize bir referans oluşturuyor, bu da sınıfınızın asla çöp toplanmadığını garanti eder. Başka bir deyişle, bir bellek sızıntısı.
pieroxy

1
@pieroxy, burada herhangi bir şey için finalize () kullanmama konusunda herkesi kabul ederken, neden kapatma kancasından bir referans olması gerektiğini anlamıyorum. Yumuşak bir referans olabilir.
Ustaman Sangat

25

Java finalize()yöntemi bir yıkıcı değildir ve uygulamanızın bağlı olduğu mantığı işlemek için kullanılmamalıdır. Java spec, finalizeyöntemin uygulamanın ömrü boyunca hiç çağrıldığının garantisi olmadığını belirtir.

Muhtemelen istediğiniz gibi bir kombinasyon finallyve bir temizleme yöntemidir:

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {

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

20

Etkili Java'ya bakın, 2. baskı sayfa 27. Madde 7: Sonlandırıcılardan kaçının

Sonlandırıcılar öngörülemez, genellikle tehlikeli ve genellikle gereksizdir. bir sonlandırıcıda asla zaman açısından kritik bir şey yapmayın. kritik kalıcı durumu güncellemek için asla bir sonlandırıcıya güvenmeyin.

Bir kaynağı sonlandırmak için bunun yerine try-finally kullanın:

// 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
ya da kaynaklarla deneme özelliğini kullanın
Gabriel Garcia

3
Bu, bir nesnenin ömrünün bir işlev kapsamında olduğunu varsayar. Tabii ki, OP'nin bahsettiği durum değil, temelde kimsenin ihtiyaç duyduğu durum da değildir. "Önbellek motoru dönüş değeri referans sayısı" nı düşünün. Son başvuru serbest bırakıldığında önbellek girdisini boşaltmak istiyorsunuz, ancak son başvuru ne zaman serbest bırakıldığını bilmiyorsunuz. finalize () bir ref sayımını azaltabilir, örneğin ... ancak kullanıcılarınızın açıkça ücretsiz bir işlevi çağırmasını istiyorsanız, bellek sızıntılarını istersiniz. genellikle her ikisini de yaparım (serbest bırakma işlevi + sonlandırmada çift kontrol ...) ...
Erik Aronesty

16

finalize()Java'da yöntem ne zaman çağrılır?

Sonlandırma yöntemi, GC nesneye artık erişilemediğini algıladıktan sonra ve nesne tarafından kullanılan belleği geri kazanmadan önce çağrılır.

  • Bir nesneye asla ulaşılamaz hale gelirse finalize(), ona asla çağrılamaz .

  • GC çalışmazsa finalize(), asla çağrılamaz. (Normalde, GC yalnızca JVM, değerli kılmak için yeterli çöp olduğuna karar verdiğinde çalışır.)

  • GC'nin belirli bir nesneye erişilemez olduğunu belirlemesi için birden fazla GC döngüsü gerekebilir. (Java GC'leri genellikle "kuşak" koleksiyonculardır ...)

  • GC bir nesneye ulaşılamaz ve sonlandırılabilir olduğunu tespit ettiğinde, bir sonlandırma kuyruğuna yerleştirilir. Sonlandırma tipik olarak normal GC ile eşzamansız olarak gerçekleşir.

(JVM spesifikasyonları aslında bir JVM'nin asla sonlandırıcıları çalıştırmamasına izin verir ... nesnelerin kullandığı alanı geri kazanmaması şartıyla. Bu şekilde uygulanan bir JVM sakat / işe yaramaz, ancak bu davranışa "izin verilir" .)

Sonuç olarak, kesin bir zaman diliminde yapılması gereken şeyleri yapmak için kesinleşmeye güvenmek akıllıca değildir. Onları hiç kullanmamak "en iyi uygulamadır". finalize()Yöntemde yapmaya çalıştığınız her şeyi yapmanın daha iyi (yani daha güvenilir) bir yolu olmalıdır .

Sonlandırma için tek meşru kullanım, uygulama kodu tarafından kaybedilen nesnelerle ilişkili kaynakları temizlemektir. O zaman bile, ilk etapta nesneleri kaybetmemesi için uygulama kodunu yazmaya çalışmalısınız. (Örneğin, 7+ Java kullanmak deneyin-ile-kaynaklar sağlamak içinclose() , her zaman çağrıldığından ...)


Finalize () yöntemi geçersiz kılınarak çağrıldığında bir dosyaya yazan bir test sınıfı oluşturdum. Yürütülmez. Biri bana neden icra edilmediğini söyleyebilir mi?

Söylemesi zor, ancak birkaç olasılık var:

  • Nesne çöp toplanmaz, çünkü hala erişilebilir durumdadır.
  • Test tamamlanmadan GC çalışmadığı için nesne çöp toplanmaz.
  • Nesne GC tarafından bulunur ve GC tarafından sonlandırma sırasına yerleştirilir, ancak testiniz tamamlanmadan sonlandırma tamamlanmaz.

10

JVM tarafından finalize () yönteminin çağrılmasında bir belirsizlik olduğundan (geçersiz kılınan finalize () yürütülüp yürütülmeyeceğinden emin değilim), çalışma amacıyla finalize () çağrıldığında ne olacağını gözlemlemenin daha iyi yolu JVM'yi komutla çöp toplama işlemini çağırmaya zorlayın System.gc().

Özellikle, bir nesne artık kullanılmadığında finalize () çağrılır. Ancak yeni nesneler yaratarak onu çağırmaya çalıştığımızda çağrısının kesinliği yoktur. Bu yüzden kesin olarak gelecekteki bir kullanımı olmayan bir nullnesne yaratıyoruz c, dolayısıyla nesnenin cson çağrısını görüyoruz .

Misal

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.");
            }
        }
    }
}

Çıktı

    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.

Not - 70'e kadar yazdırdıktan sonra ve daha sonra programda b nesnesi kullanılmadığında bile, b'nin JVM tarafından silinip temizlenmediğine dair bir belirsizlik vardır, çünkü "Bike sınıfında sonlandırma yöntemi ..." yazdırılmaz.


10
Arama System.gc();, çöp toplama işleminin gerçekten yapılacağının garantisi değildir.
Simon Forsberg

3
Ne tür bir koleksiyonun çalıştırılacağı da garanti edilmez . Java Java'ların çoğu "kuşak" toplayıcılar olduğundan önemlidir.
Stephen C

5

finalize, sınıf oluşturma sayısını basacaktır.

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);
}

ana

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

Gördüğün gibi. Aşağıdaki çıkış, gc'nin sınıf sayısı 36 olduğunda ilk kez çalıştırıldığını gösterir.

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

Son zamanlarda sonlandırıcı yöntemlerle güreştikten sonra (test sırasında bağlantı havuzlarını atmak için), sonlandırıcının birçok şeyden yoksun olduğunu söylemeliyim. Bir Java 8 ortamında (Oracle JDK, Ubuntu 15) aşağıdaki şeylerin doğru olduğunu gördüm ve gözlemlemek için VisualVM kullanma ve zayıf referanslar kullanma:

  • Sonlandırmaya derhal son verilmez Sonlandırıcı (GC kısmı) referansın ayrı ayrı sahibi
  • Varsayılan Çöp Toplayıcı, erişilemeyen nesneleri havuzlar
  • Sonlandırma, çöp toplayıcının kaynakları serbest bıraktığı belirli bir aşama olduğunu bir uygulama detayına işaret ederek çağrılır.
  • System.gc () öğesini çağırmak genellikle nesnelerin daha sık sonlandırılmasına neden olmaz, yalnızca Finalizer'ın erişilemeyen bir nesnenin daha hızlı farkına varmasına neden olur
  • Bir iplik dökümü oluşturmak neredeyse her zaman yığın dökümü veya başka bir iç mekanizma gerçekleştirilirken yüksek yığın yükü nedeniyle sonlandırıcının tetiklenmesine neden olur
  • Sonlandırma dikişleri, bellek gereksinimlerine (daha fazla bellek boşaltmaya) veya belirli bir iç sınırın sonlandırılması için işaretlenen nesnelerin listesine bağlanacaktır. Dolayısıyla, sonlandırılan çok fazla nesneniz varsa, sonlandırma aşaması yalnızca birkaç taneye kıyasla daha sık ve daha erken tetiklenir.
  • Bir System.gc () yöntemi doğrudan bir kesinleştirme tetikledi, ancak yalnızca başvurunun yerel ve kısa bir yaşam olduğu durumlar vardı. Bu nesil ile ilgili olabilir.

Son düşünce

Sonlandırma yöntemi güvenilir değildir, ancak yalnızca bir şey için kullanılabilir. Bir nesnenin, çöp toplama işleminden önce kapatılmasını veya atılmasını sağlayabilirsiniz; böylece, kullanım ömrü sonu eylemi içeren daha karmaşık bir yaşam silindirine sahip nesneler doğru bir şekilde işlenirse arıza güvenliğinin uygulanmasını mümkün kılabilirsiniz. Bunu düşünmemizin tek nedeni, onu geçersiz kılmak için buna değer.


2

Bir Nesne, herhangi bir canlı iş parçacığından veya statik referanslardan erişilemiyorsa, Çöp toplama veya GC için uygun hale gelir; diğer bir deyişle, tüm başvurular boşsa bir nesnenin çöp toplama için uygun hale geldiğini söyleyebilirsiniz. Döngüsel bağımlılıklar referans olarak sayılmaz, bu nedenle A Nesnesi B nesnesine referansı varsa ve B nesnesi A Nesnesi referansına sahipse ve başka canlı referansları yoksa, A ve B Nesneleri Çöp toplama için uygun olacaktır. Genellikle bir nesne aşağıdaki durumlarda Java'da çöp toplama için uygun hale gelir:

  1. Bu nesnenin tüm referansları açıkça null olarak ayarlanmıştır, örneğin object = null
  2. Nesne bir blok içinde oluşturulur ve denetim o bloktan çıktığında referans kapsam dışına çıkar.
  3. Bir nesne başka bir nesnenin başvurusunu tutarsa ​​ve kap nesnesinin başvurusunu null olarak ayarladığınızda, alt nesne ya da içerilen nesne otomatik olarak çöp toplama için uygun hale gelir.
  4. Bir nesnenin yalnızca WeakHashMap üzerinden canlı referansları varsa, çöp toplama için uygun olur.

Bir Eğer finalbir nesnenin alan yavaş hesaplaması sırasında defalarca kullanılır ve nesne bundan sonra asla kullanılmayacaktır, nesne son dek yaşatılacaktır kaynak kodu alanını istediğinde veya JIT bir alanını kopyalamak olabilir geçici değişken ve sonra hesaplama önce nesneyi terk?
supercat

@supercat: bir iyileştirici, kodu nesnenin ilk oluşturulmadığı bir forma yeniden yazabilir; bu durumda, senkronizasyon nesnenin kullanımı ile sonlandırıcı arasında bir sıralamayı zorlamadığı sürece kurucu bittikten hemen sonra sonlandırılabilir.
Holger

@Holger: JIT'in yaratılması ve terk edilmesi arasındaki bir nesneye olacak her şeyi görebildiği durumlarda, JIT'in finalizatörü erken ateşlemesi için herhangi bir neden görmüyorum. Asıl soru, sonlandırıcının belirli bir yöntem içinde tetiklenememesini sağlamak için kodun ne yapması gerektiğidir. .NET'te GC.KeepAlive(), GC'nin bir nesne kullanabileceğini varsaymaya zorlama dışında hiçbir şey yapmayan bir işlev vardır, ancak Java'da böyle bir işlev bilmiyorum. Bir kişi volatilebu amaç için değişken kullanabilir , ancak bir değişkeni yalnızca böyle bir amaç için kullanmak savurgan görünebilir.
supercat

@supercat: JIT kesinleşmeyi tetiklemiyor, sadece referans tutmamak için kodu düzenliyor, ancak doğrudan doğruya enqueue etmek yararlı olabilir FinalizerReference, böylece hiçbir GC bulunmadığını bulmak için bir GC döngüsüne ihtiyaç duymaz Referanslar. Eşitleme önce gerçekleşecek bir ilişki sağlamak için yeterlidir ; sonuçlandırma farklı bir iş parçacığında gerçekleşebileceğinden (aslında) genellikle resmi olarak gereklidir. Java 9 ekleyecek Reference.reachabilityFence
Holger

@Holger: JIT nesne oluşturmayı optimize Finalizeederse, JIT doğrudan bunu yapan bir kod üretmiş olsaydı , yalnızca çağrılabilirdi. Senkronizasyon kodu genellikle yalnızca tek bir iş parçacığında kullanılmasını bekleyen nesneler için beklenir mi? Bir nesne terk edilmeden önce geri alınması gereken bir işlem yaparsa (örn. Bir soket bağlantısı açmak ve diğer uçtaki kaynağa özel kullanım elde etmek), kod hala soketi kullanırken bağlantıyı kapatmak için bir sonlandırıcıya sahip olmak bir felaket olur . Kodun senkronizasyonu kullanması normal
midir

2

Sonlandırma yöntemi garanti edilmez.Bu nesne, nesne GC için uygun hale geldiğinde çağrılır. Nesnelerin çöp toplanamayacağı birçok durum vardır.


3
Yanlış. Söylediğiniz şey, bir nesneye ulaşılamaz hale geldiğinde sonlandırılmış olmasıdır. Aslında yöntem gerçekten toplandığında çağrılır.
Stephen C

2

Bazen yok edildiğinde, bir nesne bir eylemde bulunmalıdır. Örneğin, bir nesnenin dosya tanıtıcısı veya yazı tipi gibi java olmayan bir kaynağı varsa, bir nesneyi yok etmeden önce bu kaynakların serbest bırakıldığını doğrulayabilirsiniz. Böyle durumları yönetmek için java "sonlandırma" adı verilen bir mekanizma sunar. Sonlandırarak, bir nesne çöp toplayıcıdan kaldırılmak üzereyken ortaya çıkan belirli eylemleri tanımlayabilirsiniz. Bir sınıfa sonlandırıcı eklemek finalize () yöntemini tanımlamanız yeterlidir yöntemini . Java yürütme süresi, söz konusu sınıftaki bir nesneyi silmek üzereyken bu yöntemi çağırır. Kesinleştirme yöntemi () içindebir nesneyi yok etmeden önce gerçekleştirilecek eylemleri belirtirsiniz. Çöp toplayıcı, düzenli olarak artık çalışma durumuna veya dolaylı olarak referansla başka bir nesneye gönderme yapmayan nesneleri arar. Bir varlık serbest bırakılmadan önce, Java çalışma zamanı nesne üzerindeki finalize () yöntemini çağırır . Sonuçlandırmak () metodu, aşağıdaki genel formu vardır:

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

İle korunan anahtar kelime, erişim için () sonuçlandırmak sınıfsal engellenir dışında koduna göre. Finalize () işlevinin çöp toplama işleminden hemen önce çağrıldığını anlamak önemlidir . Örneğin, bir nesne kapsamdan çıktığında çağrılmaz. Bu, finalize () komutunun ne zaman yürütüleceğini veya yürütülmeyeceğini bilemeyeceğiniz anlamına gelir . Sonuç olarak, program sistem kaynaklarını veya nesne tarafından kullanılan diğer kaynakları serbest bırakmak için başka araçlar sağlamalıdır. Programın normal çalışması için finalize () işlevine güvenmemelisiniz .


1

Sonlandırma yöntemini geçersiz kıldığımız sınıf

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

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

Sonlandırma yönteminin çağrılma şansı

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

bellek döküm nesnelerle aşırı yüklendiğinde gc sonlandırma yöntemini çağırır

çalıştırılır ve sık sık çağrılan sonlandırma yöntemini bulamadığınız konsolu görürsünüz, bellek aşırı yüklenirken sonlandırma yöntemi çağrılır.


0

Java, nesnelerin çağrılabilecek finalize () adlı bir yöntemi uygulamasına izin verir.

çöp toplayıcı nesneyi toplamaya çalışırsa finalize () yöntemi çağrılır.

Çöp toplayıcı çalışmazsa, yöntem çağrılmaz.

Çöp toplayıcı nesneyi toplayamazsa ve çalıştırmaya çalışırsa yeniden , yöntem ikinci kez çağrılmaz.

Uygulamada, bunu gerçek projelerde kullanmanız pek olası değildir.

Sadece çağrılmayabileceğini ve kesinlikle iki kez çağrılmayacağını unutmayın. Finalize () yöntemi sıfır veya bir kez çalışabilir.

Aşağıdaki kodda, çöp toplayıcısını çalıştırmaya gerek kalmadan programdan çıkıldığından, finalize () yöntemi çalıştırdığımızda çıktı üretmez.

Kaynak


0

finalize()çöp toplama işleminden hemen önce çağrılır. Bir nesne kapsam dışına çıktığında çağrılmaz. Bu, ne zaman veya hatta finalize()yürütüleceğini bilemeyeceğiniz anlamına gelir .

Misal:

Programınız çöp toplayıcı oluşmadan sona ererse, finalize()yürütülmez. Bu nedenle, programınızın normal çalışmasında kullandığı araç olarak değil, diğer kaynakların düzgün şekilde işlenmesini sağlamak için veya özel kullanım uygulamaları için yedekleme yordamı olarak kullanılmalıdır.


0

İşaret edildiği gibi https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers ,

Yürütme zamanı Java Sanal Makinesi'ne (JVM) bağlı olduğu için sonlandırıcıların yürütülmesi gereken sabit bir zaman yoktur. Tek garanti, yürüten herhangi bir sonlandırıcı yönteminin, ilişkili nesneye erişilemez hale geldikten bir süre sonra (çöp toplamanın ilk döngüsü sırasında algılanır) ve çöp toplayıcının ilişkili nesnenin depolamasını geri kazanmasından (çöp toplayıcının ikinci döngüsü sırasında) . Bir nesnenin sonlandırıcısının yürütülmesi, nesneye erişilemez hale geldikten sonra keyfi olarak uzun bir süre gecikebilir. Sonuç olarak, bir nesnenin finalize () yönteminde dosya tanıtıcılarını kapatma gibi zaman açısından kritik işlevleri çağırmak sorunludur.


-3

Daha iyi anlamak için bu Programı çalıştırmayı deneyin

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();
            }
     }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.