Quando viene chiamato il metodo finalize () in Java?


330

Devo sapere quando finalize()viene chiamato il metodo in JVM. Ho creato una classe di test che scrive in un file quando il finalize()metodo viene chiamato sovrascrivendolo. Non viene eseguito. Qualcuno può dirmi il motivo per cui non viene eseguito?


34
Proprio come una nota a margine: finalizzare è contrassegnato come deprecato in Java 9
Reg

1
Dai
wleao

se qualcosa ha un riferimento al tuo oggetto o addirittura alla classe. finalize()e la garbage collection non ha alcun impatto.
ha9u63ar,

Risposte:


273

In generale, è meglio non fare affidamento su finalize()operazioni di pulizia ecc.

Secondo il Javadoc (che varrebbe la pena leggere), è:

Chiamato dal Garbage Collector su un oggetto quando Garbage Collection determina che non ci sono più riferimenti all'oggetto.

Come ha sottolineato Joachim, ciò potrebbe non accadere mai nella vita di un programma se l'oggetto è sempre accessibile.

Inoltre, il Garbage Collector non è garantito per l'esecuzione in qualsiasi momento specifico. In generale, ciò che sto cercando di dire è che finalize()probabilmente non è il metodo migliore da usare in generale a meno che non ci sia qualcosa di specifico per cui ne hai bisogno.


19
In altre parole (solo per chiarire i futuri lettori) non viene mai chiamato nella classe principale, poiché, quando la classe principale si chiude, non è necessario raccogliere rifiuti. Il sistema operativo pulisce comunque tutto ciò che l'app ha usato.
Mark Jeronimus

113
"Non è il metodo migliore da usare ... a meno che non ci sia qualcosa di specifico per cui hai bisogno" - uh, quella frase si applica al 100% di tutto, quindi non è utile. La risposta di Joachim Sauer è molto migliore
BT

1
@ Zom-B il tuo esempio è utile per chiarimenti, ma solo per essere pedante, presumibilmente potrebbe essere chiamato sulla classe principale se la classe principale crea un thread non daemon e poi ritorna?
Tom G,

3
Quindi quali sono le situazioni in cui finalizesarebbe utile?
nbro,

3
@MarkJeronimus - In realtà, questo è irrilevante. Il finalize()metodo attivo per la classe principale viene richiamato quando viene >> garbage collection di un'istanza >> della classe, non quando termina il metodo principale. Inoltre, la classe principale potrebbe essere spazzatura raccolta prima che l'applicazione finisca; ad es. in un'app multi-thread in cui il thread "principale" crea altri thread e quindi ritorna. (In pratica, sarebbe richiesto un caricatore di classi non standard ....)
Stephen C

379

Il finalizemetodo viene chiamato quando un oggetto sta per raccogliere la spazzatura. Ciò può avvenire in qualsiasi momento dopo che è diventato idoneo per la raccolta dei rifiuti.

Si noti che è del tutto possibile che un oggetto non venga mai raccolto spazzatura (e quindi finalizenon viene mai chiamato). Questo può accadere quando l'oggetto non diventa mai idoneo per gc (perché è raggiungibile per tutta la durata della JVM) o quando nessuna raccolta di rifiuti in realtà viene eseguita tra il momento in cui l'oggetto diventa idoneo e il tempo in cui la JVM smette di funzionare (ciò si verifica spesso con programmi di test).

Ci sono modi per dire alla JVM di funzionare finalizesu oggetti che non è stato ancora richiamato, ma anche usarli non è una buona idea (le garanzie di quel metodo non sono neanche molto forti).

Se ti affidi finalizeper il corretto funzionamento della tua applicazione, stai facendo qualcosa di sbagliato. finalizedovrebbe essere usato solo per la pulizia di risorse (di solito non Java). E questo è esattamente perché JVM non garantisce che finalizevenga mai chiamato su nessun oggetto.


2
@Rajesh. No. Non è un problema di "durata della vita". Puoi mettere il tuo programma in un ciclo infinito (per anni) e se il garbage collector non è necessario non funzionerà mai.
ChrisCantrell,

5
@VikasVerma: la sostituzione perfetta non è niente: non dovresti averne bisogno. L'unico caso in cui avrebbe senso è se la tua classe gestisce alcune risorse esterne (come una connessione TCP / IP, un file ... tutto ciò che il GC Java non è in grado di gestire). In questi casi l' Closableinterfaccia (e l'idea alla base) è probabilmente ciò che vuoi: .close()avvicinare / scartare la risorsa e richiedere all'utente della classe di chiamarla al momento giusto. Si potrebbe desidera aggiungere un finalizemetodo di "solo per essere Salva", ma che sarebbe più di uno strumento di debug di una correzione reale (perché non è abbastanza affidabile).
Joachim Sauer,

4
@Dragonborn: questa è in realtà una domanda completamente diversa e dovrebbe essere posta separatamente. Ci sono hook di arresto, ma non sono garantiti se la JVM si spegne inaspettatamente (aka crash). Ma le loro garanzie sono significativamente più forti di quelle per i finalizzatori (e sono anche più sicure).
Joachim Sauer,

4
Il tuo ultimo paragrafo dice di usarlo solo per ripulire le risorse anche se non vi è alcuna garanzia che verrà mai chiamato. Sta parlando questo ottimismo? Suppongo che qualcosa di inaffidabile in quanto non sarebbe adatto nemmeno per ripulire le risorse.
Jeroen Vannevel,

2
A volte i finalizzatori possono salvare la situazione ... Ho avuto un caso in cui una libreria di terze parti utilizzava un FileInputStream, senza mai chiuderlo. Il mio codice stava chiamando il codice della libreria e quindi ha cercato di spostare il file, non riuscendo perché era ancora aperto. Ho dovuto forzare la chiamata System.gc()per invocare FileInputStream :: finalize (), quindi ho potuto spostare il file.
Elista l'

73
protected void finalize() throws Throwable {}
  • ogni classe eredita il finalize()metodo da java.lang.Object
  • il metodo viene chiamato dal Garbage Collector quando determina che non esistono più riferimenti all'oggetto
  • il metodo Finalize Object non esegue azioni ma può essere ignorato da qualsiasi classe
  • normalmente dovrebbe essere sovrascritto per ripulire le risorse non Java, ovvero chiudere un file
  • se l'override finalize()è una buona pratica di programmazione usare un'istruzione try-catch-finally e chiamare sempre super.finalize(). Questa è una misura di sicurezza per assicurarti di non perdere inavvertitamente la chiusura di una risorsa utilizzata dalla classe che chiama gli oggetti

    protected void finalize() throws Throwable {
         try {
             close();        // close open files
         } finally {
             super.finalize();
         }
     }
  • qualsiasi eccezione generata finalize()durante la garbage collection interrompe la finalizzazione ma viene altrimenti ignorata

  • finalize() non viene mai eseguito più di una volta su nessun oggetto

citato da: http://www.janeg.ca/scjp/gc/finalize.html

Puoi anche controllare questo articolo:


25
L'articolo JavaWorld a cui ti colleghi è del 1998 e contiene alcuni consigli interessanti, in particolare il suggerimento di chiamare System.runFinalizersOnExit () per garantire che i finalizzatori vengano eseguiti prima dell'uscita di JVM. Tale metodo è attualmente deprecato, con il commento 'Questo metodo è intrinsecamente pericoloso. Può comportare la chiamata di finalizzatori su oggetti live mentre altri thread manipolano contemporaneamente quegli oggetti, con conseguente comportamento irregolare o deadlock. " Quindi non lo farò.
Greg Chabala,

3
Poiché runFinalizerOnExit () NON è thread-safe, ciò che si potrebbe fare è Runtime.getRuntime (). AddShutdownHook (new Thread () {public void run () {destroyMyEnclosingClass ();}}); nel costruttore della classe.
Ustaman Sangat,

2
@Ustaman Sangat Questo è un modo per farlo, ma ricorda che questo imposta un riferimento alla tua istanza da shutdownHook, che praticamente garantisce che la tua classe non venga mai raccolta. In altre parole, è una perdita di memoria.
pieroxy,

1
@pieroxy, mentre sono d'accordo che tutti gli altri qui riguardo a non usare finalize () per nulla, non vedo perché ci dovrebbe essere un riferimento dal gancio di spegnimento. Si potrebbe avere un riferimento morbido.
Ustaman Sangat,

25

Il finalize()metodo Java non è un distruttore e non deve essere utilizzato per gestire la logica da cui dipende l'applicazione. Le specifiche Java indicano che non esiste alcuna garanzia che il finalizemetodo venga chiamato durante il tempo di vita dell'applicazione.

Quello che probabilmente vuoi è una combinazione di finallye un metodo di pulizia, come in:

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {

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

20

Dai un'occhiata a Effective Java, 2nd edition pagina 27. Articolo 7: Evita i finalizzatori

I finalizzatori sono imprevedibili, spesso pericolosi e generalmente non necessari. mai fare qualcosa di critico in un finalizzatore. non dipendere mai da un finalizzatore per aggiornare lo stato critico persistente.

Per terminare una risorsa, utilizzare invece try-finally:

// 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
oppure usa try-with-resources
Gabriel Garcia,

3
Ciò presuppone che la durata di un oggetto rientri nell'ambito di una funzione. Il che, ovviamente, non è il caso a cui si riferisce l'OP, né è fondamentalmente il caso di cui tutti hanno bisogno. Pensa "conteggio dei riferimenti al valore di ritorno del motore cache". Vuoi liberare la voce della cache quando viene liberato l'ultimo riferimento, ma non sai quando viene liberato l'ultimo riferimento. finalize () può decrementare un conteggio di ref, ad esempio ... ma se richiedi ai tuoi utenti di chiamare esplicitamente una funzione gratuita, stai chiedendo perdite di memoria. di solito faccio solo entrambi (funzione di rilascio + doppio controllo nel finalizzare ...) ...
Erik Aronesty,

16

Quando viene finalize()chiamato il metodo in Java?

Il metodo finalize verrà chiamato dopo che il GC ha rilevato che l'oggetto non è più raggiungibile e prima di recuperare effettivamente la memoria utilizzata dall'oggetto.

  • Se un oggetto non diventa mai irraggiungibile, finalize()non verrà mai chiamato su di esso.

  • Se il GC non funziona, finalize()potrebbe non essere mai chiamato. (Normalmente, il GC funziona solo quando la JVM decide che è probabile che ci sia abbastanza spazzatura per renderlo utile.)

  • Potrebbe essere necessario più di un ciclo GC prima che il GC determini che un oggetto specifico non è raggiungibile. (I GC Java sono in genere collezionisti "generazionali" ...)

  • Quando il GC rileva che un oggetto è irraggiungibile e finalizzabile, viene inserito in una coda di finalizzazione. La finalizzazione in genere avviene in modo asincrono con il normale GC.

(Le specifiche JVM in realtà consentono a una JVM di non farlo mai eseguire finalizzatori ... purché non recuperi lo spazio utilizzato dagli oggetti. Una JVM implementata in questo modo sarebbe paralizzata / inutile, ma se questo comportamento è "consentito" .)

Il risultato è che non è saggio fare affidamento sulla finalizzazione per fare le cose che devono essere fatte in un determinato periodo di tempo. È "buona pratica" non usarli affatto. Dovrebbe esserci un modo migliore (cioè più affidabile) di fare qualunque cosa tu stia cercando di fare nel finalize()metodo.

L'unico uso legittimo per la finalizzazione è la pulizia delle risorse associate agli oggetti che sono stati persi dal codice dell'applicazione. Anche in questo caso, dovresti provare a scrivere il codice dell'applicazione in modo che non perda in primo luogo gli oggetti. (Ad esempio, utilizzare Java 7+ try-with-resources per assicurarsi che close()sia sempre chiamato ...)


Ho creato una classe di test che scrive in un file quando viene chiamato il metodo finalize () sovrascrivendolo. Non viene eseguito. Qualcuno può dirmi il motivo per cui non viene eseguito?

È difficile da dire, ma ci sono alcune possibilità:

  • L'oggetto non è garbage collection perché è ancora raggiungibile.
  • L'oggetto non è garbage collection perché il GC non viene eseguito prima del termine del test.
  • L'oggetto viene trovato dal GC e inserito nella coda di finalizzazione dal GC, ma la finalizzazione non viene completata prima del termine del test.

10

Poiché esiste un'incertezza nel chiamare il metodo finalize () da parte di JVM (non sono sicuro se finalize () che viene sovrascritto verrebbe eseguito o meno), ai fini dello studio il modo migliore per osservare cosa succede quando viene chiamato finalize (), è quello di impone a JVM di chiamare garbage collection tramite comando System.gc().

In particolare, finalize () viene chiamato quando un oggetto non è più in uso. Ma quando proviamo a chiamarlo creando nuovi oggetti non c'è certezza della sua chiamata. Quindi per certezza creiamo un nulloggetto cche ovviamente non ha alcun uso futuro, quindi vediamo la cchiamata finalizzata dell'oggetto .

Esempio

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

Produzione

    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.

Nota - Anche dopo aver stampato fino a 70 e dopo il quale l'oggetto b non viene utilizzato nel programma, non vi è incertezza sul fatto che b sia cancellato o meno da JVM poiché "Metodo di finalizzazione chiamato in classe Bike ..." non viene stampato.


10
La chiamata System.gc();non è una garanzia che verrà effettivamente eseguita la Garbage Collection.
Simon Forsberg,

3
Inoltre, non è garantito quale tipo di raccolta verrà eseguita. Rilevante poiché la maggior parte dei GC Java sono collezionisti "generazionali".
Stephen C,

5

finalize stamperà il conteggio per la creazione della classe.

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

principale

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

Come potete vedere. Il seguente risultato mostra che gc è stato eseguito la prima volta quando il conteggio delle classi è 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

Dopo aver lottato con i metodi del finalizzatore di recente (al fine di smaltire i pool di connessioni durante i test), devo dire che il finalizzatore manca di molte cose. Usando VisualVM per osservare e usando riferimenti deboli per tracciare l'interazione effettiva, ho scoperto che le seguenti cose sono vere in un ambiente Java 8 (Oracle JDK, Ubuntu 15):

  • Finalize non viene chiamato immediatamente Finalizer (parte GC) individualmente elusivamente il riferimento
  • Il Garbage Collector predefinito raggruppa oggetti non raggiungibili
  • Finalize viene chiamato in blocco indicando un dettaglio dell'implementazione che esiste una certa fase in cui il Garbage Collector libera le risorse.
  • La chiamata a System.gc () spesso non comporta la finalizzazione più frequente degli oggetti, ma comporta solo che il Finalizer venga a conoscenza di un oggetto non raggiungibile più rapidamente
  • La creazione di un dump del thread provoca quasi sempre l'attivazione del finalizzatore a causa dell'elevato sovraccarico dell'heap durante l'esecuzione del dump dell'heap o di altri meccanismi interni
  • Le giunzioni di finalizzazione devono essere vincolate dai requisiti di memoria (liberare più memoria) o dall'elenco di oggetti contrassegnati per la finalizzazione che aumenta di un certo limite interno. Quindi, se molti oggetti vengono finalizzati, la fase di finalizzazione verrà attivata più spesso e prima rispetto a pochi
  • Ci sono state circostanze in cui System.gc () ha attivato direttamente una finalizzazione, ma solo se il riferimento era una vita locale e breve. Questo potrebbe essere legato alla generazione.

Pensiero finale

Il metodo Finalize non è affidabile ma può essere utilizzato solo per una cosa. Puoi assicurarti che un oggetto sia stato chiuso o eliminato prima che fosse spazzato via, rendendo possibile l'implementazione di un sistema di sicurezza se gli oggetti con un ciclo di vita più complesso che coinvolgono un'azione di fine vita sono gestiti correttamente. Questa è l'unica ragione a cui riesco a pensare che ne valga la pena per annullarla.


2

Un oggetto diventa idoneo per Garbage Collection o GC se non è raggiungibile da thread attivi o riferimenti statici in altre parole, si può dire che un oggetto diventa idoneo per Garbage Collection se tutti i suoi riferimenti sono nulli. Le dipendenze cicliche non vengono conteggiate come riferimento, quindi se l'oggetto A ha un riferimento all'oggetto B e l'oggetto B ha un riferimento all'oggetto A e non hanno nessun altro riferimento attivo, entrambi gli oggetti A e B saranno idonei per la Garbage Collection. Generalmente un oggetto diventa idoneo per la garbage collection in Java nei seguenti casi:

  1. Tutti i riferimenti di quell'oggetto sono esplicitamente impostati su null, ad es. Oggetto = null
  2. L'oggetto viene creato all'interno di un blocco e il riferimento esce dall'ambito una volta che il controllo esce da quel blocco.
  3. L'oggetto padre impostato su null, se un oggetto contiene il riferimento di un altro oggetto e quando si imposta il riferimento dell'oggetto contenitore su null, l'oggetto figlio o contenuto diventa automaticamente idoneo per la garbage collection.
  4. Se un oggetto ha solo riferimenti attivi tramite WeakHashMap, sarà idoneo per la garbage collection.

Se un finalcampo di un oggetto viene utilizzato ripetutamente durante un calcolo lento e l'oggetto non verrà mai utilizzato successivamente, l'oggetto verrebbe mantenuto in vita fino all'ultimo quando il codice sorgente richiede il campo o la JIT potrebbe copiare il campo in un variabile temporanea e quindi abbandonare l'oggetto prima del calcolo?
supercat

@supercat: un ottimizzatore può riscrivere il codice in un modulo in cui l'oggetto non viene creato in primo luogo; in tal caso, potrebbe essere finalizzato subito dopo il completamento del costruttore, a meno che la sincronizzazione non imponga un ordinamento tra l'uso dell'oggetto e il finalizzatore.
Holger,

@Holger: Nei casi in cui la JIT può vedere tutto ciò che accadrà mai a un oggetto tra la sua creazione e l'abbandono, non vedo alcun motivo per cui la JIT licenzierà presto il finalizzatore. La vera domanda sarebbe quale codice deve fare per garantire che il finalizzatore non possa essere attivato con un metodo particolare. In .NET esiste una GC.KeepAlive()funzione che non fa altro che forzare il GC ad assumere che potrebbe usare un oggetto, ma non conosco alcuna funzione in Java. Si potrebbe usare la volatilevariabile a tale scopo, ma l'utilizzo di una variabile esclusivamente a tale scopo sembrerebbe dispendioso.
supercat,

@supercat: JIT non attiva la finalizzazione, organizza semplicemente il codice per non mantenere un riferimento, tuttavia, potrebbe essere utile accodare direttamente il FinalizerReference, in modo che non abbia bisogno di un ciclo GC per scoprire che non ci sono Riferimenti. La sincronizzazione è sufficiente per garantire una relazione accada prima ; poiché la finalizzazione può (in realtà è) in esecuzione in un thread diverso, spesso è comunque formalmente necessaria. Java 9 aggiungerà Reference.reachabilityFence...
Holger

@Holger: se JIT ottimizza la creazione di oggetti, l'unico che Finalizeverrebbe chiamato sarebbe se JIT producesse codice che lo ha fatto direttamente. In genere il codice di sincronizzazione dovrebbe essere previsto per gli oggetti che prevedono di essere utilizzati solo in un singolo thread? Se un oggetto esegue un'azione che deve essere annullata prima di essere abbandonata (ad es. Apertura di una connessione socket e acquisizione dell'uso esclusivo della risorsa sull'altra estremità), avere un finalizzatore chiudere la connessione mentre il codice sta ancora utilizzando il socket sarebbe un disastro . Sarebbe normale che il codice utilizzasse la sincronizzazione ...
supercat,

2

il metodo finalize non è garantito. Questo metodo viene chiamato quando l'oggetto diventa idoneo per GC. Ci sono molte situazioni in cui gli oggetti potrebbero non essere raccolti.


3
Non corretto. Quello che stai dicendo è che un oggetto è finalizzato quando diventa irraggiungibile. In realtà viene chiamato quando il metodo viene effettivamente raccolto.
Stephen C,

2

A volte, quando viene distrutto, un oggetto deve compiere un'azione. Ad esempio, se un oggetto ha una risorsa non java come un handle di file o un font, è possibile verificare che queste risorse vengano rilasciate prima di distruggere un oggetto. Per gestire tali situazioni, java offre un meccanismo chiamato "finalizzazione". Completandolo, è possibile definire azioni specifiche che si verificano quando un oggetto sta per essere rimosso dal Garbage Collector. Per aggiungere un finalizzatore a una classe è sufficiente definire il metodo finalize () . Il tempo di esecuzione Java chiama questo metodo ogni volta che sta per eliminare un oggetto di quella classe. Entro la finalizzazione metodo ()si specificano le azioni da eseguire prima di distruggere un oggetto. Il garbage collector viene periodicamente cercato oggetti che non fanno più riferimento a uno stato in esecuzione o indirettamente a qualsiasi altro oggetto con riferimento. Prima che una risorsa venga rilasciata, il runtime Java chiama il metodo finalize () sull'oggetto. Il metodo finalize () ha la seguente forma generale:

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

Con la parola chiave protetta , viene impedito l' accesso a finalize () tramite codice esterno alla sua classe. È importante capire che finalize () viene chiamato appena prima della garbage collection. Ad esempio, non viene chiamato quando un oggetto lascia l'ambito. Significa che non puoi sapere quando, o se, finalize () verrà eseguito. Di conseguenza, il programma deve fornire altri mezzi per liberare risorse di sistema o altre risorse utilizzate dall'oggetto. Non dovresti fare affidamento su finalize () per il normale funzionamento del programma.


1

Classe in cui sovrascriviamo il metodo finalize

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

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

Le possibilità di finalizzare il metodo vengono chiamate

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

quando la memoria è sovraccarica di oggetti dump, gc chiamerà il metodo finalize

esegui e vedi la console, dove non trovi il metodo finalize chiamato frequentemente, quando la memoria viene sovraccaricata, verrà chiamato il metodo finalize.


0

Java consente agli oggetti di implementare un metodo chiamato finalize () che potrebbe essere chiamato.

Il metodo finalize () viene chiamato se il garbage collector tenta di raccogliere l'oggetto.

Se il Garbage Collector non viene eseguito, il metodo non viene chiamato.

Se il Garbage Collector non riesce a raccogliere l'oggetto e tenta di eseguirlo nuovamente, il metodo non viene chiamato la seconda volta.

In pratica, è molto improbabile che lo utilizzi in progetti reali.

Tieni presente che potrebbe non essere chiamato e che sicuramente non verrà chiamato due volte. Il metodo finalize () potrebbe essere eseguito zero o una volta.

Nel codice seguente, il metodo finalize () non produce alcun output quando lo eseguiamo poiché il programma termina prima che sia necessario eseguire garbage collector.

fonte


0

finalize()viene chiamato appena prima della raccolta dei rifiuti. Non viene chiamato quando un oggetto esce dall'ambito. Ciò significa che non puoi sapere quando o anche se finalize()verrà eseguito.

Esempio:

Se il programma termina prima che si verifichi Garbage Collector, finalize()non verrà eseguito. Pertanto, dovrebbe essere utilizzato come procedura di backup per garantire la corretta gestione di altre risorse o per applicazioni di uso speciale, non come mezzo utilizzato dal programma durante il normale funzionamento.


0

Come sottolineato in https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers ,

Non esiste un tempo fisso in cui i finalizzatori devono essere eseguiti perché il tempo di esecuzione dipende dalla Java Virtual Machine (JVM). L'unica garanzia è che qualsiasi metodo finalizzatore che eseguirà lo farà qualche volta dopo che l'oggetto associato è diventato irraggiungibile (rilevato durante il primo ciclo di Garbage Collector) e qualche tempo prima che il Garbage Collector recuperi la memoria dell'oggetto associato (durante il secondo ciclo del Garbage Collector) . L'esecuzione del finalizzatore di un oggetto può essere ritardata per un tempo arbitrariamente lungo dopo che l'oggetto diventa irraggiungibile. Di conseguenza, richiamare funzionalità time-critical come la chiusura di handle di file nel metodo finalize () di un oggetto è problematico.


-3

Prova a eseguire questo programma per una migliore comprensione

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();
            }
     }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.