2009-06-16 12 views
15

Cosa succede se si salva un riferimento all'oggetto corrente durante la chiamata finalizzata? Ad esempio:Riferimento all'oggetto durante la finalizzazione

class foo { 
    ... 
    public void finalize() { 
     bar.REFERENCE = this; 
    } 
} 

L'oggetto viene raccolto o no? Cosa succede quando tenti di accedere a bar.REFERENCE in seguito?

+4

+1 perché è una buona domanda, ma spero che questo sia stato solo un esercizio intellettuale. ;) –

+0

non ti preoccupare, era :) –

risposta

11

L'oggetto non è garbage collection. Questo è conosciuto come "Resurrezione degli oggetti".

Devi stare attento con questo, una volta che il finalizzatore è chiamato il gc non chiamerà di nuovo, in alcuni ambienti come .NET è possibile ri-registrare il finalizzatore, ma io non sono sicuro di java

6

Questo genere di cose è la ragione per cui l'uso di finalize() è generalmente scoraggiato.

+0

Finalizza dovrebbe essere utilizzato solo per liberare i riferimenti alle risorse non gestite. Il GC si prenderà cura di tutti i riferimenti gestiti per te alla fine. –

+6

No, finalize NON deve essere usato per quello, perché viene eseguito in un momento successivo arbitrario, o per niente. Le risorse non gestite dovrebbero essere liberate esplicitamente in un blocco finale.Nel migliore dei casi, finalize() può essere un ulteriore fail safe. –

+1

... ma anche come soluzione di sicurezza, è molto problematico. Poiché non è deterministico, trasformerà una perdita di risorse riproducibile in una fuga di risorse intermittenti, che si verifica meno spesso, ma è molto più difficile da riprodurre. Ci sono stato, fatto quello :-(. – sleske

1

Il metodo finalize() può essere invocato esplicitamente sull'istanza foo oppure può essere richiamato dal garbage collector quando tenta di recuperare lo spazio occupato da tale oggetto.

Se bar è un'istanza valida, imposta il campo REFERENCE sull'istanza foo. Dal punto di vista del garbage collector, questo aumenta il conteggio dei riferimenti di foo.

Se un'eccezione viene generata all'interno del metodo finalize() (ad esempio come un NullPointerException causa bar essere null), allora il processo termina finalizzazione semplicemente.

N.B. Come altri hanno sottolineato ... il tuo esempio è sicuramente qualcosa da evitare.

9

Se è assolutamente necessario resuscitare gli oggetti, questo articolo JavaWorld suggerisce di creare un'istanza nuova anziché resuscitare l'istanza in fase di completamento perché se l'istanza in fase di definizione diventa nuovamente idonea per la raccolta verrà semplicemente raccolta (il finalizzatore non verrà eseguito ancora).

0

Poiché Java è un linguaggio di sicurezza e la piattaforma, la memoria non viene liberata. Anche gli associati PhantomReference s non saranno accodati sui loro ReferenceQueue s. La VM chiamerà sempre finalize su un oggetto una sola volta. C'è un bel diagramma di stato nella specifica JVM.

In genere se si utilizza un finalizzatore, è necessario lasciare la dichiarazione come @Override protected void finalize() throws Throwable, in modo da non disturbare l'API. Ancora meglio usare un finaliser protetto, come in 1st Ed efficace di Java.

Questo particolare trucco ha colpito i titoli di testa (del San Jose Mercury, comunque) quando un gruppo di Princeton lo usava per costruire un codice personalizzato ClassLoader da codice non affidabile. Sebbene la specifica sia stata leggermente rafforzata (il costruttore Object deve terminare l'esecuzione normalmente prima che il finalizzatore possa essere chiamato, specificato in J2SE 5.0, implementato in Java SE 6), rimane comunque un'area problematica. Se stai progettando un'API, assicurati che le classi sensibili non possano essere sottoclassi e risparmia loro molto dolore.

Problemi correlati