No .NET, em quais circunstâncias devo usar GC.SuppressFinalize()
?
Que vantagem (s) usando esse método me oferece?
No .NET, em quais circunstâncias devo usar GC.SuppressFinalize()
?
Que vantagem (s) usando esse método me oferece?
Respostas:
SuppressFinalize
só deve ser chamado por uma classe que tenha um finalizador. Ele está informando ao Garbage Collector (GC) que o this
objeto foi totalmente limpo.
O IDisposable
padrão recomendado quando você tem um finalizador é:
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, o CLR mantém abas nos objetos com um finalizador quando eles são criados (tornando-os mais caros de criar). SuppressFinalize
informa ao GC que o objeto foi limpo corretamente e não precisa ir para a fila do finalizador. Parece um destruidor de C ++, mas não age como um.
A SuppressFinalize
otimização não é trivial, pois seus objetos podem ficar muito tempo aguardando na fila do finalizador. Não fique tentado a chamar SuppressFinalize
outros objetos, lembre-se. Esse é um defeito sério esperando para acontecer.
As diretrizes de design nos informam que um finalizador não é necessário se o seu objeto for implementado IDisposable
, mas se você tiver um finalizador, deverá implementá-lo IDisposable
para permitir a limpeza determinística da sua classe.
Na maioria das vezes você deve se safar IDisposable
para limpar recursos. Você só precisa de um finalizador quando seu objeto se apega a recursos não gerenciados e precisa garantir que esses recursos sejam limpos.
Nota: Às vezes, os codificadores adicionam um finalizador para depurar construções de suas próprias IDisposable
classes, a fim de testar se o código descartou seu IDisposable
objeto corretamente.
public void Dispose() // Implement IDisposable
{
Dispose(true);
#if DEBUG
GC.SuppressFinalize(this);
#endif
}
#if DEBUG
~MyClass() // the finalizer
{
Dispose(false);
}
#endif
IDisposable
não for sealed
, ela deve incluir a chamada GC.SuppressFinalize(this)
mesmo que não inclua um finalizador definido pelo usuário . Isso é necessário para garantir a semântica adequada para tipos derivados que adicionam um finalizador definido pelo usuário, mas substituem apenas o Dispose(bool)
método protegido .
sealed
como mencionado por @SamHarwell é importante para as classes derivadas. O CodeAnalysis resulta em ca1816 + ca1063 quando a classe não é selada, mas as classes seladas são boas sem SuppressFinalize
.
SupressFinalize
informa ao sistema que qualquer trabalho que tenha sido realizado no finalizador já foi realizado, portanto, o finalizador não precisa ser chamado. Nos documentos do .NET:
Objetos que implementam a interface IDisposable podem chamar esse método a partir do método IDisposable.Dispose para impedir que o coletor de lixo chame Object.Finalize em um objeto que não o exija.
Em geral, a maioria dos Dispose()
métodos deve ser capaz de chamar GC.SupressFinalize()
, porque deve limpar tudo o que seria limpo no finalizador.
SupressFinalize
é apenas algo que fornece uma otimização que permite ao sistema não incomodar na fila do objeto no encadeamento do finalizador. Um Dispose()
finalizador / gravado corretamente deve funcionar corretamente com ou sem uma chamada para GC.SupressFinalize()
.
Esse método deve ser chamado no Dispose
método de objetos que implementa o IDisposable
, assim o GC não chamaria o finalizador outra vez se alguém chamar o Dispose
método.
Consulte: Método GC.SuppressFinalize (Object) - Microsoft Docs
Dispose(true);
GC.SuppressFinalize(this);
Se o objeto tiver finalizador, .net colocará uma referência na fila de finalização.
Desde que ligamos Dispose(ture)
, ele limpa o objeto, portanto não precisamos da fila de finalização para fazer este trabalho.
Então, GC.SuppressFinalize(this)
remova a referência na fila de finalização.
Se uma classe, ou qualquer coisa dela derivada, puder conter a última referência ao vivo para um objeto com um finalizador, um GC.SuppressFinalize(this)
ou GC.KeepAlive(this)
deve ser chamado no objeto após qualquer operação que possa ser afetada adversamente por esse finalizador, garantindo assim que o finalizador vence só será executado após a conclusão da operação.
O custo de GC.KeepAlive()
e GC.SuppressFinalize(this)
é essencialmente o mesmo em qualquer classe que não tenha um finalizador, e as classes que têm finalizadores geralmente devem chamar GC.SuppressFinalize(this)
; portanto, Dispose()
nem sempre é necessário usar a última função como a última etapa de , mas não será necessário. estar errado.