2013-05-15 2 views
13

La documentazione sulla PowerShell here ha il seguente commento interessante in esso:Perché questa variabile deve essere impostata su null dopo che l'oggetto è stato eliminato?

PowerShell powershell = PowerShell.Create(); 

using (powershell) 
{ 
    //... 
} 

// Even after disposing of the PowerShell object, we still 
// need to set the powershell variable to null so that the 
// garbage collector can clean it up. 
powershell = null; 

Perché powershell deve essere impostato su null dopo essere smaltiti?

+2

Questa è una domanda C#, non una domanda PowerShell. –

+1

@AnsgarWiechers - Sei corretto; dopo aver esaminato il collegamento, però, è uno schema strano. Qualcuno può dire perché non hanno usato 'usando (PowerShell powershell = PowerShell.Create()) {'? Preferenza di stile? –

+8

Per la cronaca questa è una pratica generalmente scarsa e semplicemente non è affatto necessaria in questo contesto. È improbabile che faccia alcuna differenza e, se lo fosse, sarebbe minuscolo. La variabile in realtà dovrebbe essere appena stata creata all'interno di "using", ma anche senza farlo, non c'è davvero alcuna giustificazione per annullarla. Il resto del metodo completerà * molto * rapidamente e l'oggetto PowerShell non consumerà un numero significativo di risorse una volta eliminato. – Servy

risposta

16

Non è direttamente un problema di PowerShell. Quando un blocco using termina, gli oggetti specificati hanno i loro metodi Dispose() chiamati. Questi in genere eseguono alcune operazioni di pulizia, spesso per evitare perdite di memoria e così via. Tuttavia, Dispose() non elimina l'oggetto. Se esiste ancora un riferimento al blocco using (come in questo esempio), l'oggetto stesso è ancora in ambito. Non può essere raccolto come garbage perché c'è ancora un riferimento ad esso, quindi sta ancora occupando memoria.

Quello che stanno facendo nel tuo esempio è cadere quel riferimento. Quando powershell è impostato su null, l'oggetto PowerShell a cui puntava è orfano, poiché non vi sono altre variabili che si riferiscono ad esso. Una volta che il garbage collector lo ha scoperto, può liberare la memoria. Ciò accadrebbe comunque alla fine del metodo (perché powershell andrebbe fuori dal campo di applicazione), ma in questo modo le risorse di sistema verranno ripristinate un po 'prima.

(Edit: Come Brian Rasmussen fa notare, il runtime .NET è estremamente intelligente sulla raccolta dei rifiuti Una volta che raggiunge l'ultimo riferimento alla powershell nel codice, il runtime dovrebbe rilevare che non ne hai bisogno. e quindi la riga powershell = null; non sta facendo nulla.)

A proposito, questo schema mi sembra molto strano. L'approccio comune è qualcosa di simile:

using (PowerShell powershell = PowerShell.Create()) 
{ 
    //... 
} 

In questo modo, powershell va fuori portata alla fine del blocco using, subito dopo che è smaltito. È più facile dire dove è rilevante la variabile e si salva del codice perché non è più necessaria la riga powershell = null. Direi anche che questa è una pratica di codifica migliore, perché powershell non esiste mai in uno stato già disposto. Se qualcuno modifica il tuo codice originale e prova a usare powershell al di fuori del blocco using, qualsiasi cosa accada sarà probabilmente negativa.

+6

Il runtime .NET non richiede riferimenti null e rileva oggetti che sono idonei per la raccolta non appena non vengono più referenziati (ovvero ciò avviene in genere prima della fine del metodo). –

+0

@Justin Morgan Re il modello sembra strano, beh sarebbe coerente con il resto della qualità del campione di codice quindi immagino ;-) – noonand

+0

@BrianRasmussen Ottimo punto! Il che significa che è ancora meno utile farlo. –

7

Non è necessario che sia impostato su null e in realtà non dovrebbe esserlo. Il garbage collector .NET è in grado di rilevare che un oggetto non viene utilizzato dopo una particolare istruzione, anche se il codice non assegna un valore nullo alla variabile corrispondente. (Vedere http://blogs.msdn.com/b/cbrumme/archive/2003/04/19/51365.aspx per i dettagli.) Per quanto riguarda un esempio "ufficiale" contiene questo codice extra con commenti fuorvianti, anche i documenti possono avere bug ...

1

Il consiglio è errato, purché sia ​​irraggiungibile sia idoneo per la spazzatura collezione. (Vedi What is the correct way to free memory in C# per qualche codice che illustrano questo) le uniche ragioni null cose sono

  • Per facilitare risolvere perdite di memoria
  • per rimuovere i riferimenti (ad esempioproprietà pubbliche) che il GC può avere difficoltà a determinare sono irraggiungibili

Entrambi i quali si dovrebbe davvero fare solo all'interno di un oggetti Dispose metodo