Perché il metodo finalize è incluso in Java?

44

Secondo questo post , non dovremmo mai fare affidamento sul metodo finalize da chiamare. Quindi perché Java l'ha incluso nel linguaggio di programmazione?

Sembra una decisione terribile includere in qualsiasi linguaggio di programmazione una funzione che potrebbe ricevere.

    
posta patstuart 25.06.2014 - 19:07
fonte

7 risposte

41

Secondo Effective Java (Seconda edizione) di Joshua Bloch, ci sono due scenari in cui finalize() è utile:

  1. One is to act as a “safety net” in case the owner of an object forgets to call its explicit termination method. While there’s no guarantee that the finalizer will be invoked promptly, it may be better to free the resource late than never, in those (hopefully rare) cases when the client fails to call the explicit termination method. But the finalizer should log a warning if it finds that the resource has not been terminated

  2. A second legitimate use of finalizers concerns objects with native peers. A native peer is a native object to which a normal object delegates via native methods. Because a native peer is not a normal object, the garbage collector doesn’t know about it and can’t reclaim it when its Java peer is reclaimed. A finalizer is an appropriate vehicle for performing this task, assuming the native peer holds no critical resources. If the native peer holds resources that must be terminated promptly, the class should have an explicit termination method, as described above. The termination method should do whatever is required to free the critical resource.

Per ulteriori informazioni, consultare il punto 7, pagina 27.

    
risposta data 25.06.2014 - 22:38
fonte
55

I finalizzatori sono importanti per la gestione delle risorse native. Ad esempio, l'oggetto potrebbe dover allocare un WidgetHandle dal sistema operativo utilizzando un'API non Java. Se non rilasci WidgetHandle quando il tuo oggetto è GC, perderai WidgetHandles.

Ciò che è importante è che il "finalizzatore non venga mai chiamato" i casi si abbattano piuttosto semplicemente:

  1. Il programma si arresta rapidamente
  2. L'oggetto "vive per sempre" durante la vita del programma
  3. Il computer si spegne / il tuo processo viene ucciso dal sistema operativo / etc

In tutti e tre questi casi, non hai una perdita nativa (in virtù del fatto che il tuo programma non è più in esecuzione), o hai già un non -perative leak (se continui ad allocare oggetti gestiti senza che siano GC'd).

L'avvertimento "non fare affidamento sul finalizzatore chiamato" riguarda davvero il fatto di non utilizzare i finalizzatori per la logica del programma. Ad esempio, non vuoi tenere traccia di quanti dei tuoi oggetti esistono in tutte le istanze del tuo programma incrementando un contatore in un file da qualche parte durante la costruzione e decrementandolo in un finalizzatore - perché non c'è alcuna garanzia che i tuoi oggetti essere finalizzato, questo contatore di file probabilmente non tornerà mai a 0. Questo è davvero un caso particolare del principio più generale che non dovresti dipendere dal fatto che il tuo programma termini normalmente (interruzioni di corrente, ecc.).

Per la gestione delle risorse native, tuttavia, i casi in cui il finalizzatore non viene eseguito corrispondono ai casi in cui non ti interessa se non viene eseguito.

    
risposta data 25.06.2014 - 20:26
fonte
5

Lo scopo di questo metodo è spiegato nella documentazione dell'API come segue:

it is invoked if and when the Java virtual machine has determined that there is no longer any means by which this object can be accessed by any thread that has not yet died, except as a result of an action taken by the finalization of some other object or class which is ready to be finalized...

the usual purpose of finalize... is to perform cleanup actions before the object is irrevocably discarded. For example, the finalize method for an object that represents an input/output connection might perform explicit I/O transactions to break the connection before the object is permanently discarded...

Se sei anche interessato ai motivi per cui i designer di lingua hanno scelto che "l'oggetto è irrevocabilmente scartato" ( garbage collection ) che va oltre il controllo del programmatore di applicazioni ("non dovremmo mai fare affidamento"), questo è stato spiegato in una risposta alla domanda correlata :

automatic garbage collection... eliminates entire classes of programming errors that bedevil C and C++ programmers. You can develop Java code with confidence that the system will find many errors quickly and that major problems won't lay dormant until after your production code has shipped..

La citazione di sopra, a sua volta, è stata presa dalla documentazione ufficiale sugli obiettivi di progettazione Java , che è può essere considerato un riferimento autorevole che spiega perché i progettisti del linguaggio Java hanno deciso in questo modo.

Per una discussione agnostica più dettagliata e linguistica di questa preferenza, consulta OOSC sezione 9.6 Gestione automatica della memoria (in realtà, non solo questa sezione, ma l'intero capitolo 9 è molto utile da leggere se sei interessato a cose del genere). Questa sezione si apre con una dichiarazione univoca:

A good O-O environment should offer an automatic memory management mechanism which will detect and reclaim unreachable objects, allowing application developers to concentrate on their job — application development.

The preceding discussion should suffice to show how important it is to have such a facility available. In the words of Michael Schweitzer and Lambert Strether:

An object-oriented program without automatic memory management is roughly the same as a pressure cooker without a safety valve: sooner or later the thing is sure to blow up!

    
risposta data 25.06.2014 - 19:18
fonte
4

I finalizzatori esistono perché dovevano essere un mezzo efficace per garantire che le cose venissero ripulite (anche se in pratica non lo sono), e perché quando sono state inventate, i mezzi migliori per garantire la pulizia (come i riferimenti fantasma e try-with-resources) non esisteva ancora. Con il senno di poi, Java sarebbe probabilmente meglio se lo sforzo per implementare la sua funzione "finalizza" fosse stato speso in altri modi di ripulire, ma ciò non era chiaro durante il periodo di sviluppo di Java.

    
risposta data 02.07.2014 - 18:26
fonte
3

CAVEAT: Potrei non essere aggiornato, ma questa è la mia comprensione di alcuni anni fa:

In generale, non vi è alcuna garanzia di quando viene eseguito un finalizzatore, o addirittura che funzioni, anche se alcune JVM ti consentono di richiedere un GC completo e la finalizzazione prima che il programma esca (il che, ovviamente, significa che il il programma impiega più tempo per uscire e quale non è la modalità operativa predefinita).

E alcuni GC erano noti per ritardare o evitare in modo esplicito oggetti GC contenenti finalizzatori, nella speranza che ciò avrebbe prodotto prestazioni migliori sui benchmark.

Questi comportamenti sfortunatamente sono in conflitto con i motivi originali raccomandati dai finalizzatori e hanno invece incoraggiato l'uso di metodi di spegnimento esplicitamente chiamati.

Se hai un oggetto che deve essere ripulito prima di essere scartato, e se davvero non puoi fidarti degli utenti di farlo, un finalizzatore può ancora valere la pena di essere preso in considerazione. Ma in generale, ci sono buone ragioni per non vederli così spesso nel moderno codice Java come hai fatto in alcuni dei primi esempi.

    
risposta data 26.06.2014 - 01:47
fonte
1

La Guida allo stile di Google Java contiene alcuni saggi consigli sul oggetto:

It is extremely rare to override Object.finalize.

Tip: Don't do it. If you absolutely must, first read and understand Effective Java Item 7, "Avoid Finalizers," very carefully, and then don't do it.

    
risposta data 26.06.2014 - 06:36
fonte
1

Specifiche del linguaggio Java (Java SE 7) afferma:

Finalizers provide a chance to free up resources that cannot be freed automatically by an automatic storage manager. In such situations, simply reclaiming the memory used by an object would not guarantee that the resources it held would be reclaimed.

    
risposta data 02.07.2014 - 15:17
fonte

Leggi altre domande sui tag