finalize() è un mezzo per eseguire bit finale di codice immediatamente prima che l'oggetto è pronto per la raccolta dei rifiuti (quando l'oggetto non ha forte riferimento ad esso).
Quindi quando dovrebbe essere utilizzato? Solo nelle presenti due casi:
- Come sicurezza per assicurarsi che un certo servizio viene chiusa o qualche cambiamento finale desiderato è fatto. Ad esempio, la classe InputStream lo utilizza per chiudere il flusso di i/o. Ad esempio, hai creato un'istanza di BufferedInputStream. Manualmente dopo averlo usato uno è supponiamo di chiuderlo(). Ma perché si può dimenticare di farlo, finalize() atto è come una rete di sicurezza per chiudere() il flusso.
- Mentre utilizzando Native's. Poiché Garbage Collector non ha alcun controllo sugli oggetti nativi , finalize() può essere utilizzato come mezzo per riprenderlo.
Oltre ai due casi precedenti, non utilizzarlo mai. Per capire perché? abbiamo bisogno di capire il funzionamento e il ciclo di vita di un oggetto.
Introduzione: esiste un thread daemon separato chiamato thread di finalizzazione responsabile della chiamata al metodo finalize(). La coda di finalizzazione è il punto in cui sono collocati gli oggetti che sono pronti per essere chiamati metodo finalize().
- Quando viene creato un oggetto, JVM controlla se l'oggetto ha un metodo finalize(). Se ha allora nota internamente che questo particolare oggetto ha il metodo finalize().
Quando un oggetto è pronto per la raccolta dei rifiuti, poi i garbage collector filo controlla se questo particolare oggetto contiene finalizzare() dalla tabella di cui (1).
2a) Se non allora è inviato per la raccolta dei rifiuti.
2b) È ha, quindi viene aggiunto alla coda di finalizzazione. E rimuove la voce dell'oggetto dalla tabella (1).
Il thread del finalizzatore continua a interrogare la coda. Per ogni oggetto in coda, viene chiamato il metodo finalize(). Dopo aver chiamato il ciclo finalize() da (2) viene nuovamente ripetuto. Se questo oggetto non ha ancora un riferimento forte, quindi inviato per GC. Se ha poi SEMPRE (2a) è chiamato perché la voce è stata eliminata in (2b)
Basically finalize() method is only called once.
Allora qual è il problema con il ciclo di cui sopra?
Da (1). È necessario più tempo per la creazione di oggetti. L'allocazione della memoria in Java è 5x a 10 volte più veloce di malloc/calloc ecc. Tutto il tempo guadagnato viene perso nella procedura di annotazione dell'oggetto nella tabella, ecc. Una volta l'ho provato. Crea 100000 oggetti in un ciclo e misura il tempo impiegato dal programma per terminare in 2 casi: uno senza finalize(), il secondo con finalize(). Trovato per essere il 20% più veloce.
Da (2b): perdita di memoria e carenza di cibo. Se l'oggetto nella coda ha riferimenti a molte risorse di memoria, allora tutti questi oggetti non verranno liberati a meno che questo oggetto non sia pronto per GC. Se tutti gli oggetti sono oggetti pesanti, allora ci può essere una carenza.
Da (2b): Perché finalize() viene chiamato una sola volta, cosa succede se in te finalize() hai un forte riferimento a "questo" oggetto. La prossima volta che finalie dell'oggetto() non viene mai chiamato, quindi può lasciare l'oggetto in uno stato incoerente.
Se all'interno finalize() viene generata un'eccezione, viene ignorata.
Non si sa quando finalize() viene chiamato poiché non si ha controllo su quando viene chiamato GC. A volte può capitare che stiate stampando il valore in finalize() ma l'output non viene mai mostrato, perché il vostro programma potrebbe essere terminato prima che venga chiamato finalize().
Quindi evitare di utilizzarlo. Piuttosto, crea un metodo dire dispose() che chiuderà le risorse necessarie o per il registro finale, ecc. the complete post on it. Spero che questo chiarisca.
solo tenere presente che il comportamento del GC dipende dall'implementazione, quindi cambierà tra le VM. –