Quando dovrei usare GC.SuppressFinalize ()?
-
02-07-2019 - |
Domanda
In .NET, in quali circostanze dovrei usare GC.SuppressFinalize ()
?
Quali vantaggi mi offre questo metodo?
Soluzione
SuppressFinalize deve essere chiamato solo da una classe che ha un finalizzatore. Sta informando il Garbage Collector (GC) che questo
oggetto è stato ripulito completamente.
Lo schema IDisposable raccomandato quando si dispone di un finalizzatore è:
public class MyClass : IDisposable
{
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// called via myClass.Dispose().
// OK to use any private object references
}
// Release unmanaged resources.
// Set large fields to null.
disposed = true;
}
}
public void Dispose() // Implement IDisposable
{
Dispose(true);
GC.SuppressFinalize(this);
}
~MyClass() // the finalizer
{
Dispose(false);
}
}
Normalmente, il CLR tiene sotto controllo gli oggetti con un finalizzatore quando vengono creati (rendendoli più costosi da creare). SuppressFinalize dice al GC che l'oggetto è stato ripulito correttamente e non ha bisogno di andare nella coda del finalizzatore. Sembra un distruttore C ++, ma non si comporta come uno.
L'ottimizzazione di SuppressFinalize non è banale, poiché i tuoi oggetti possono vivere a lungo in attesa sulla coda del finalizzatore. Non essere tentato di chiamare SuppressFinalize su altri oggetti, intendiamoci. È un grave difetto che attende di accadere.
Le linee guida di progettazione ci informano che un finalizzatore non è necessario se il tuo oggetto implementa IDisposable, ma se hai un finalizzatore devi implementare IDisposable per consentire la pulizia deterministica della tua classe.
Il più delle volte dovresti riuscire a cavartela con IDisposable per ripulire le risorse. Dovresti aver bisogno di un finalizzatore solo quando il tuo oggetto si attacca a risorse non gestite e devi garantire che tali risorse vengano ripulite.
Nota: a volte i programmatori aggiungono un finalizzatore per eseguire il debug di build delle proprie classi IDisposable al fine di verificare che il codice abbia disposto correttamente il proprio oggetto IDisposable.
public void Dispose() // Implement IDisposable
{
Dispose(true);
#if DEBUG
GC.SuppressFinalize(this);
#endif
}
#if DEBUG
~MyClass() // the finalizer
{
Dispose(false);
}
#endif
Altri suggerimenti
stai dicendo al sistema che qualsiasi lavoro sarebbe stato fatto nel finalizzatore è già stato fatto, quindi il finalizzatore non ha bisogno di essere chiamato. Dai documenti .NET:
Oggetti che implementano IDisposable l'interfaccia può chiamare questo metodo da il metodo IDisposable.Dispose a impedire al garbage collector di chiamando Object.Finalize su un oggetto che non lo richiede.
In generale, la maggior parte dei metodi Dispose () dovrebbe essere in grado di chiamare GC.SupressFinalize (), perché dovrebbe ripulire tutto ciò che verrebbe ripulito nel finalizzatore.
SupressFinalize è solo qualcosa che fornisce un'ottimizzazione che consente al sistema di non disturbare l'accodamento dell'oggetto al thread del finalizzatore. Un Dispose () / finalizzatore correttamente scritto dovrebbe funzionare correttamente con o senza una chiamata a GC.SupressFinalize ().
Questo metodo deve essere chiamato sul metodo Dispose degli oggetti che implementano l'IDisposable, in questo modo il GC non chiamerebbe il finalizzatore un'altra volta se qualcuno chiama il metodo Dispose.
Vedi: http://msdn.microsoft.com /en-us/library/system.gc.suppressfinalize.aspx
Dispose(true);
GC.SuppressFinalize(this);
Se l'oggetto ha un finalizzatore, .net inserisce un riferimento nella coda di finalizzazione
Dato che abbiamo chiamato Dispose (ture), cancella l'oggetto, quindi non abbiamo bisogno di una coda di finalizzazione per fare questo lavoro.
Quindi chiama GC.SuppressFinalize (questo) rimuovi il riferimento nella coda di finalizzazione.
Se una classe, o qualsiasi cosa derivata da essa, potrebbe contenere l'ultimo riferimento attivo a un oggetto con un finalizzatore, allora GC.SuppressFinalize (this)
o GC.KeepAlive (this )
dovrebbe essere chiamato sull'oggetto dopo qualsiasi operazione che potrebbe essere influenzata negativamente da quel finalizzatore, assicurando così che il finalizzatore non verrà eseguito fino al completamento dell'operazione.
Il costo di GC.KeepAlive ()
e GC.SuppressFinalize (this)
sono essenzialmente gli stessi in qualsiasi classe che non ha un finalizzatore, e le classi che i finalizzatori dovrebbero generalmente chiamare GC.SuppressFinalize (this)
, quindi utilizzare quest'ultima funzione come ultimo passaggio di Dispose ()
potrebbe non essere sempre necessario, ma ha vinto ' essere in errore.