¿Cuándo debo usar GC.SuppressFinalize()?
En .NET, ¿bajo qué circunstancias debo utilizar GC.SuppressFinalize()
?
¿Qué ventaja(s) me aporta utilizar este método?
SuppressFinalize
solo debe ser llamado por una clase que tenga un finalizador. Está informando al recolector de basura (GC) que el this
objeto se limpió por completo.
El patrón recomendado IDisposable
cuando 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). SuppressFinalize
le 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 SuppressFinalize
optimizació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 SuppressFinalize
a 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 IDisposable
para permitir una limpieza determinista de su clase.
La mayoría de las veces deberías poder salirte con la tuya IDisposable
para 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 IDisposable
clases para probar que el código haya eliminado su IDisposable
objeto correctamente.
public void Dispose() // Implement IDisposable
{
Dispose(true);
#if DEBUG
GC.SuppressFinalize(this);
#endif
}
#if DEBUG
~MyClass() // the finalizer
{
Dispose(false);
}
#endif
SupressFinalize
le 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.
SupressFinalize
es 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()
.
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.