374 Stimmen

Wann sollte ich GC.SuppressFinalize() verwenden?

In .NET, unter welchen Umständen sollte ich verwenden GC.SuppressFinalize() ?

Welche(r) Vorteil(e) bringt mir die Anwendung dieser Methode?

380voto

Robert Paulson Punkte 16995

SuppressFinalize sollte nur von einer Klasse aufgerufen werden, die einen Finalizer hat. Er teilt dem Garbage Collector (GC) mit, dass this Objekt wurde vollständig bereinigt.

Die empfohlene IDisposable Muster, wenn Sie einen Finalizer haben, ist:

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);
    }
}

Normalerweise behält die CLR Objekte mit einem Finalizer im Auge, wenn sie erstellt werden (was ihre Erstellung verteuert). SuppressFinalize teilt dem GC mit, dass das Objekt ordnungsgemäß aufgeräumt wurde und nicht in die Finalizer-Warteschlange gestellt werden muss. Er sieht aus wie ein C++-Destruktor, verhält sich aber nicht wie einer.

Le SuppressFinalize Optimierung ist nicht trivial, da Ihre Objekte sehr lange in der Finalizer-Warteschlange stehen können. Lassen Sie sich nicht dazu verleiten, die SuppressFinalize auf andere Objekte, wohlgemerkt. Das ist ein schwerwiegender Fehler, der nur darauf wartet, zu passieren.

Design-Richtlinien informieren uns, dass ein Finalizer nicht notwendig ist, wenn Ihr Objekt IDisposable , aber wenn Sie einen Finalizer haben, sollten Sie IDisposable um die deterministische Bereinigung Ihrer Klasse zu ermöglichen.

Die meiste Zeit sollten Sie damit auskommen können IDisposable um die Ressourcen zu bereinigen. Sie sollten nur dann einen Finalizer benötigen, wenn Ihr Objekt auf nicht verwaltete Ressourcen zugreift und Sie sicherstellen müssen, dass diese Ressourcen bereinigt werden.

Hinweis: Manchmal fügen Programmierer einen Finalizer zu ihren eigenen Debug-Builds hinzu IDisposable Klassen, um zu prüfen, ob der Code ihre IDisposable Objekt ordnungsgemäß.

public void Dispose() // Implement IDisposable
{
    Dispose(true);
#if DEBUG
    GC.SuppressFinalize(this);
#endif
}

#if DEBUG
~MyClass() // the finalizer
{
    Dispose(false);
}
#endif

52voto

Michael Burr Punkte 320591

SupressFinalize teilt dem System mit, dass die Arbeit, die im Finalizer erledigt worden wäre, bereits erledigt ist, so dass der Finalizer nicht aufgerufen werden muss. Aus den .NET-Dokumenten:

Objekte, die t implementieren Schnittstelle implementieren, können diese Methode von der Methode IDisposable.Dispose aufrufen, um zu verhindern, dass der Garbage Collector von Object.Finalize für ein Objekt aufruft, das dies nicht benötigt.

Generell gilt, dass fast alle Dispose() Methode sollte in der Lage sein, die GC.SupressFinalize() denn es sollte alles bereinigen, was im Finalizer bereinigt werden würde.

SupressFinalize ist nur eine Optimierung, die es dem System ermöglicht, das Objekt nicht in die Warteschlange des Finalizer-Threads zu stellen. Eine richtig geschriebene Dispose() /finalizer sollte mit oder ohne einen Aufruf von GC.SupressFinalize() .

6voto

Max CHien Punkte 133
Dispose(true);
GC.SuppressFinalize(this);

Wenn das Objekt einen Finalizer hat, stellt .net eine Referenz in die Finalisierungswarteschlange.

Da wir den Aufruf Dispose(true) wird das Objekt gelöscht, so dass wir keine Finalisierungswarteschlange für diese Aufgabe benötigen.

Rufen Sie also GC.SuppressFinalize(this) Referenz in der Finalisierungswarteschlange entfernen.

2voto

supercat Punkte 72939

Wenn eine Klasse oder etwas von ihr Abgeleitetes den letzten lebenden Verweis auf ein Objekt mit einem Finalizer enthält, dann kann entweder GC.SuppressFinalize(this) ou GC.KeepAlive(this) sollte für das Objekt nach jeder Operation aufgerufen werden, die von diesem Finalizer beeinträchtigt werden könnte, um sicherzustellen, dass der Finalizer erst nach Abschluss dieser Operation ausgeführt wird.

Die Kosten für GC.KeepAlive() y GC.SuppressFinalize(this) sind in jeder Klasse, die keinen Finalizer hat, im Wesentlichen gleich, und Klassen, die Finalizer haben, sollten generell GC.SuppressFinalize(this) so dass die Verwendung der letztgenannten Funktion als letzter Schritt von Dispose() ist vielleicht nicht immer notwendig, aber auch nicht verkehrt.

-1voto

albertein Punkte 25058

Diese Methode muss auf dem Dispose Methode von Objekten, die die IDisposable Auf diese Weise würde der GC den Finalizer nicht ein weiteres Mal aufrufen, wenn jemand die Dispose Methode.

Siehe: GC.SuppressFinalize(Object) Methode - Microsoft Docs

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X