L’impostazione degli oggetti Java su null fa più qualcosa?

Stavo sfogliando alcuni vecchi libri e ho trovato una copia di “Practical Java” di Peter Hagger. Nella sezione delle prestazioni, vi è un consiglio per impostare i riferimenti agli oggetti su null quando non sono più necessari.

In Java, l’impostazione dei riferimenti agli oggetti su null migliora l’efficienza delle prestazioni o della raccolta dei rifiuti? In tal caso, in quali casi si tratta di un problema? Classi di contenitori? Composizione dell’object? Classi interiori anonime?

Lo vedo molto spesso nel codice. Questo è ormai un consiglio di programmazione ormai obsoleto o è ancora utile?

Dipende un po ‘da quando stavi pensando di azzerare il riferimento.

Se si ha una catena di oggetti A-> B-> C, una volta che A non è raggiungibile, A, B e C saranno tutti idonei per la garbage collection (supponendo che nient’altro si riferisca a B o C). Non è necessario, e non è mai stato necessario, impostare in modo esplicito i riferimenti A-> B o B-> C su null, ad esempio.

A parte questo, la maggior parte delle volte il problema non si pone, perché in realtà hai a che fare con gli oggetti nelle raccolte. In generale, dovresti sempre pensare di rimuovere oggetti dagli elenchi, dalle mappe ecc. Chiamando il metodo appropriato remove ().

Il caso in cui vi era un consiglio per impostare i riferimenti a null era specificamente in un ambito lungo in cui un object ad uso intensivo della memoria cessava di essere utilizzato a metà dell’ambito . Per esempio:

 { BigObject obj = ... doSomethingWith(obj); obj = null; <-- explicitly set to null doSomethingElse(); } 

La logica era che, poiché obj è ancora in ambito, quindi senza il nesso esplicito del riferimento, non diventa garbage collectable fino a quando non viene completato il metodo doSomethingElse () . E questo è il consiglio che probabilmente non tiene più sulle JVM moderne : si scopre che il compilatore JIT può calcolare a che punto un determinato riferimento all'object locale non è più utilizzato.

No, non è un consiglio obsoleto. I riferimenti penzolanti sono ancora un problema, specialmente se si è, ad esempio, implementando un contenitore di array espandibile ( ArrayList o simile) utilizzando una matrice pre-allocata. Gli elementi oltre la dimensione “logica” dell’elenco devono essere annullati, altrimenti non verranno liberati.

Vedere Java 2a ed efficace, elemento 6: Eliminare riferimenti di oggetti obsoleti.

Campi di istanza, elementi di array

Se esiste un riferimento a un object, non può essere raccolto. Soprattutto se quell’object (e l’intero grafico dietro di esso) è grande, c’è solo un riferimento che sta fermando la raccolta dei dati inutili, e quel riferimento non è più necessario, è una situazione sfortunata.

I casi patologici sono l’object che conserva un’istanza non correlata all’intero albero DOM XML utilizzato per configurarlo, all’MBean che non è stato registrato, o al riferimento singolo a un object proveniente da un’applicazione Web non distribuita che impedisce l’estrazione di un intero classloader. .

Quindi, a meno che tu non sia sicuro che l’object che detiene il riferimento stesso sarà comunque triturato (o anche in quel caso), dovresti annullare tutto ciò che non ti serve più.

Variabili scoped:

Se stai pensando di impostare una variabile locale su null prima della fine del suo ambito, in modo che possa essere recuperata dal garbage collector e contrassegnarla come “inutilizzabile d’ora in poi”, dovresti considerare di metterla in un ambito più limitato .

 { BigObject obj = ... doSomethingWith(obj); obj = null; // <-- explicitly set to null doSomethingElse(); } 

diventa

 { { BigObject obj = ... doSomethingWith(obj); } // <-- obj goes out of scope doSomethingElse(); } 

Gli ambiti lunghi e piatti sono generalmente negativi per la leggibilità del codice. Anche l'introduzione di metodi privati ​​per rompere le cose solo per quello scopo non è inaudita.

In ambienti di restrizione della memoria (ad esempio telefoni cellulari) questo può essere utile. Impostando null, l’object non ha bisogno di aspettare che la variabile esca dallo scope per essere gc’d.

Per la programmazione di tutti i giorni, tuttavia, questa non dovrebbe essere la regola, tranne in casi speciali come quello citato da Chris Jester-Young.

Innanzitutto, non significa nulla che stai impostando un object su null. Lo spiego qui sotto:

 List list1=new ArrayList(); List list2=list1; 

Nel segmento di codice sopra quello che stiamo facendo, in realtà stiamo creando il nome della variabile di riferimento object list1 di ArrayList Object che è memorizzato nella memoria. Quindi list1 si riferisce a quell’object e ne rileva più di una variabile. E nella seconda riga del codice stiamo copiando il riferimento di list1 in list2. Quindi ora tornando alla tua domanda se lo faccio:

 list1=null; 

ciò significa che list1 non si riferisce più a nessun object che è memorizzato nella memoria, quindi list2 non avrà nulla da riferire. Quindi se controlli la dimensione di list2:

 list2.size(); //it gives you 0 

Quindi qui arriva il concetto di garbage collector che dice “non ti preoccupi di liberare la memoria che è contenuta nell’object, lo farò quando scoprirò che non verrà più utilizzato nel programma e JVM mi gestirà”.

Spero che chiarisca il concetto.

Uno dei motivi per farlo è eliminare i riferimenti agli oggetti obsoleti. Puoi leggere il testo qui.