2010-10-21 16 views
10

Ho chiesto a un question su questo metodo:Quando smaltire e perché?

// Save an object out to the disk 
public static void SerializeObject<T>(this T toSerialize, String filename) 
{ 
    XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType()); 
    TextWriter textWriter = new StreamWriter(filename); 

    xmlSerializer.Serialize(textWriter, toSerialize); 
    textWriter.Close(); 
} 

nella risposta che ho ricevuto questo come un'osservazione aggiunto:

Assicurarsi di sempre smaltire risorse disponibili, come ruscelli e lettori di testo e scrittori. Questo non sembra essere il caso nel tuo metodo SerializeObject.

Quindi, posso dire che questo sembrerà superfelico per qualcuno che ha codificato C# per un anno o due, ma perché devo smaltirlo?

Si vede che testWriter ha un metodo di smaltimento, ma la raccolta dei dati inutili non dovrebbe occuparsene? Sono venuto da Delfi a C#. In Delphi ho dovuto ripulire tutto, quindi questo non è il caso di me che voglio essere pigro. Mi è stato appena detto che se costringi a liberare la memoria che i tuoi oggetti occupano, allora può causare cose cattive. Mi è stato detto di "Lascia fare il garbage collector".

  1. Quindi, perché è necessario chiamare dispose? (La mia ipotesi è che sia perché il textWriter colpisce il disco.)
  2. C'è una lista di oggetti con cui devo stare attento? (O un modo semplice per sapere quando devo chiamare dispose?)
+1

Correlati: http://stackoverflow.com/questions/1691846/does-garbage-collector-call-dispose –

+0

La mia comprensione è che fa sì che il GC a sappi che questo è pronto per la raccolta, invece di dover controllare per vedere se è pronto.Inoltre, puoi dire al GC di raccogliere "in anticipo" su questo elemento, invece del framework che vi si appende per un po '"just in case" http://www.devx.com/dotnet/Article/33167 – jcolebrand

+4

@drachenstern - malinteso popolare, ma errato. Dispose ti fornisce semplicemente un meccanismo per chiudere forzatamente le risorse non gestite come handle di file o socket di rete non appena hai finito con loro senza aspettare il garbage collector. Non segnala al GC di raccogliere l'oggetto. – Paolo

risposta

12

È corretto che per codice scritto correttamente il GC pulirà le risorse native. L'oggetto avrà un finalizzatore e durante la finalizzazione libererà le risorse native necessarie.

Tuttavia, quando ciò accade è molto non deterministico. Inoltre è un po 'arretrato perché stai usando il GC che ha progettato di gestire la memoria gestita come mezzo per gestire le risorse native.Questo porta a casi interessanti e può causare risorse native per rimanere in vita più a lungo del previsto che porta a situazioni in cui

  • file sono aperti molto tempo dopo che non sono più utilizzati
  • maniglie delle risorse possono esaurirsi perché il GC doesn' vedere abbastanza memoria per forzare una raccolta e quindi eseguire i finalizzatori

Il modello di utilizzo/disposizione aggiunge determinismo alla pulizia delle risorse native e rimuove questi problemi.

1

Se si sta aprendo una risorsa (ad esempio un file o si apre una connessione al database), lo smaltimento della risorsa rilascerà la sua presa sulla risorsa . Se non lo fai, altre persone potrebbero non essere in grado di connettersi al database o utilizzare il file.

Come regola generale .... se la classe implementa l'interfaccia IDisposable, è necessario chiamare il metodo Dispose() al termine. Più che probabile che ci fosse un motivo per renderli usa e getta :)

2

Se si utilizzano risorse native (ad esempio handle di file), è necessario chiamare Dispose() per chiuderle presto, e non quando il GC viene eseguito (quale potrebbe essere molto più tardi nelle generazioni gc più alte). E si desidera chiudere il file poiché l'accesso ai file di solito blocca il file in qualche modo.

4

Se sai che non userai una certa risorsa, puoi semplicemente eliminarla da solo; sarai sicuramente più veloce del garbage collector e consentirai ad altri di usare il file o qualunque cosa tu abbia aperto più velocemente. Il modo più semplice sarebbe quella di utilizzare il vostro TextWriter o qualsiasi altra risorsa in un using:

using (TextWriter textWriter = new StreamWriter(filename)) 
{ 
    xmlSerializer.Serialize(textWriter, toSerialize); 
} 

Questo assicura fondamentalmente la TextWriter è disposto alla fine. Non ne hai più bisogno, comunque.

+3

probabilmente non è necessario eseguire entrambi Chiudi e Disponi –

+0

@Conrad si, lo so. Ho lasciato il suo codice per lo più così com'era, solo per mostrargli che c'è poco che ha bisogno di cambiare. – alex

4

Il garbage collector rilascia tutte le risorse, ma l'ora in cui viene eseguita non è definita. Il metodo Dispose fornisce un modo per rilasciare immediatamente risorse non gestite.

+0

"Garbage collector rilascia tutte le risorse" Non necessariamente: immagina l'oggetto che Bob ha sottoscritto a un evento di un oggetto di maggiore durata (ad esempio AppDomain). Il GC non pulirà mai Bob se non gli dici di annullare l'iscrizione a quell'evento! – Niki

+0

Giusto, GC chiama il finalizzatore, è responsabilità dello sviluppatore di classe liberare risorse in Dispose/finalizer. Stavo parlando di utilizzare classi .NET monouso, come TextWriter dalla domanda, che sono (si spera) scritte correttamente. –

15

La regola generale qui è piuttosto semplice: chiama sempre Dispose() sugli oggetti che implementano IDisposable (non tutti gli oggetti lo fanno). Non si sa sempre il motivo per cui un oggetto ha dovuto implementare Dispose, ma si deve presumere che sia lì per un motivo.

Il modo più semplice per essere sicuri di farlo è attraverso using:

using (TextWriter tw = new StreamWriter(fileName)) 
{ 
    // your code here 
} 

Questo chiamerà Dispose() automaticamente alla fine del blocco utilizzando (è fondamentalmente lo stesso che utilizza un blocco try/catch/finally con il Dispose() nel blocco finally).

Per ulteriori informazioni su come Dispose funziona con la garbage collection, see here.

0

Il netturbino "si prenderà cura di questo". Presto o tardi. Quando arriva a chiamare il finalizzatore, dopo la successiva garbage collection.

La chiamata Dispose assicura che le risorse (come i file handle) vengano rilasciate il prima possibile, rendendole così disponibili per il riutilizzo da parte di altri processi nel sistema. La maggior parte delle volte non noterai la differenza tra chiamare lo Dispose e lasciare che il garbage collector lo gestisca. Ma ci sono momenti in cui lo farai. Un crawler Web, ad esempio, che crea molti oggetti HttpWebResponse, esaurirà rapidamente le connessioni se non le smaltisci dopo l'uso. (Non che io abbia incontrato questo problema ... no, non io.)

0

Il motivo per chiamare Dispose piuttosto che attendere il GC è spesso perché si sta utilizzando una risorsa di sistema limitata che si desidera rilasciare come il più rapidamente possibile in modo che altri processi o thread possano usarlo. Per gli oggetti con lo schema IDisposable, il costrutto "using" è un modo facile e leggibile per assicurarsi che venga chiamato Dispose.

1

Dalla documentazione TextWriter.Dispose:

Nota Chiamare sempre Dispose prima di rilasciare tuo ultimo riferimento alla TextWriter. In caso contrario, le risorse utilizzate non verranno liberate fino al il garbage collector chiama il metodo Finalize dell'oggetto TextWriter.

Dalla documentazione Object.Finalize:

L'ora esatta in cui il finalizzatore esegue durante la raccolta dei rifiuti è indefinito.Le risorse non sono garantite per essere rilasciate in qualsiasi momento specifico , a meno che non si chiami un metodo Chiudi o un metodo Dispose.

e

Il metodo Finalize potrebbe non funzionare a completamento o potrebbe non funzionare affatto in le seguenti eccezionali circostanze:

  • Altri blocchi Finalizer indefinitamente (va in un ciclo infinito, prova a ottenere un blocco che non può mai ottenere e presto). Poiché il runtime tenta di eseguire i finalizzatori per il completamento, altri finalizzatori potrebbero non essere chiamati se un finalizzatore blocca indefinitamente.

  • Il processo termina senza dare a il runtime una possibilità di pulizia. Nel caso , la prima notifica delruntime del processo è una notifica DLL_PROCESS_DETACH.

Il runtime continua a finalizzare oggetti durante l'arresto solo quando il numero di oggetti finalizable continua a diminuire.

0

In genere è necessario disporre gli oggetti quando non sono più necessari.

L'oggetto di smontaggio non appena terminato con essi significherà che bloccherà l'accesso ad altre applicazioni/elaborate.

3

Beh, in realtà lo stai già disponendo poiché il metodo textWriter.Close lo fa.

public virtual void Close() 
{ 
    this.Dispose(true); 
    GC.SuppressFinalize(this); 
} 

Quindi è possibile modificare il codice in. Questo

public static void SerializeObject<T>(this T toSerialize, String filename) 
{ 
    TextWriter textWriter; 
    try 
    { 
     XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType()); 
     textWriter = new StreamWriter(filename); 

      xmlSerializer.Serialize(textWriter, toSerialize); 
    } 
    finally 
    { 
     textWriter.Close(); 
    } 

Che è molto simile a quello che usa() nelle altre risposte.

L'impatto di questo non è che se si verifica un errore con Serialize, ci vorrà un po 'di tempo prima che il Framework rinunci al blocco del file (quando Elabora la coda fReachable).

So che FxCop ti dice quando impiantare IDisposable ma non penso che ci sia un modo semplice per scoprire quando è necessario chiamare Dispose oltre che guardare i documenti e vedere se un oggetto implora IDisposable (o intellisense).

0

Un programmatore che pensa che non ci si debba preoccupare di smaltire le cose perché un finalizzatore si prenderà cura di loro è come un guidatore che pensa che non ci si debba preoccupare di evitare collisioni perché l'auto ha un airbag. Sì, un airbag renderà le cose più resistenti, ma ...

+0

Risposta non molto utile ... –

+0

Ci sono molti motivi per cui un finalizzatore non può essere eseguito in modo tempestivo; mentre ci sono alcune situazioni in cui potrebbe non essere pratico smaltire le cose in modo deterministico (ad esempio perché una risorsa è condivisa da un numero sconosciuto di oggetti) quasi tutti i programmi che si basano su un finalizzatore per il corretto funzionamento dovrebbero generalmente essere considerati danneggiati. – supercat

Problemi correlati