Domanda

In .NET, in quali circostanze dovrei usare GC.SuppressFinalize () ?

Quali vantaggi mi offre questo metodo?

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top