¿Cuándo debo usar GC.SuppressFinalize()?

Resuelto GEOCHET asked hace 16 años • 5 respuestas

En .NET, ¿bajo qué circunstancias debo utilizar GC.SuppressFinalize()?

¿Qué ventaja(s) me aporta utilizar este método?

GEOCHET avatar Sep 30 '08 05:09 GEOCHET
Aceptado

SuppressFinalizesolo debe ser llamado por una clase que tenga un finalizador. Está informando al recolector de basura (GC) que el thisobjeto se limpió por completo.

El patrón recomendado IDisposablecuando tienes un finalizador es:

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, el CLR controla los objetos con un finalizador cuando se crean (lo que hace que su creación sea más costosa). SuppressFinalizele dice al GC que el objeto se limpió correctamente y no necesita pasar a la cola del finalizador. Parece un destructor de C++, pero no actúa como tal.

La SuppressFinalizeoptimización no es trivial, ya que sus objetos pueden vivir mucho tiempo esperando en la cola del finalizador. No caigas en la tentación de recurrir SuppressFinalizea otros objetos. Ése es un defecto grave que está a punto de suceder.

Las pautas de diseño nos informan que no es necesario un finalizador si su objeto implementa IDisposable, pero si tiene un finalizador debe implementarlo IDisposablepara permitir una limpieza determinista de su clase.

La mayoría de las veces deberías poder salirte con la tuya IDisposablepara limpiar los recursos. Solo debería necesitar un finalizador cuando su objeto retenga recursos no administrados y necesite garantizar que esos recursos se limpien.

Nota: A veces, los programadores agregarán un finalizador para depurar compilaciones de sus propias IDisposableclases para probar que el código haya eliminado su IDisposableobjeto correctamente.

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

#if DEBUG
~MyClass() // the finalizer
{
    Dispose(false);
}
#endif
Robert Paulson avatar Sep 29 '2008 23:09 Robert Paulson

SupressFinalizele dice al sistema que cualquier trabajo que se hubiera realizado en el finalizador ya se realizó, por lo que no es necesario llamar al finalizador. De los documentos .NET:

Los objetos que implementan la interfaz IDisposable pueden llamar a este método desde el método IDisposable.Dispose para evitar que el recolector de basura llame a Object.Finalize en un objeto que no lo requiere.

En general, la mayoría de los Dispose()métodos deberían poder llamar a GC.SupressFinalize(), porque debería limpiar todo lo que se limpiaría en el finalizador.

SupressFinalizees simplemente algo que proporciona una optimización que permite que el sistema no se moleste en poner el objeto en cola en el subproceso finalizador. Un /finalizer correctamente escrito Dispose()debería funcionar correctamente con o sin una llamada a GC.SupressFinalize().

Michael Burr avatar Sep 29 '2008 22:09 Michael Burr
Dispose(true);
GC.SuppressFinalize(this);

Si el objeto tiene finalizador, .net coloca una referencia en la cola de finalización.

Como tenemos una llamada Dispose(true), se borra el objeto, por lo que no necesitamos una cola de finalización para realizar este trabajo.

Entonces llame GC.SuppressFinalize(this)a eliminar referencia en la cola de finalización.

Max CHien avatar Apr 16 '2018 01:04 Max CHien