In .NET, under which circumstances should I use GC.SuppressFinalize()
?
What advantage(s) does using this method give me?
In .NET, under which circumstances should I use GC.SuppressFinalize()
?
What advantage(s) does using this method give me?
SuppressFinalize
should only be called by a class that has a finalizer. It's informing the Garbage Collector (GC) that this
object was cleaned up fully.
The recommended IDisposable
pattern when you have a finalizer is:
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);
}
}
Normally, the CLR keeps tabs on objects with a finalizer when they are created (making them more expensive to create). SuppressFinalize
tells the GC that the object was cleaned up properly and doesn't need to go onto the finalizer queue. It looks like a C++ destructor, but doesn't act anything like one.
The SuppressFinalize
optimization is not trivial, as your objects can live a long time waiting on the finalizer queue. Don't be tempted to call SuppressFinalize
on other objects mind you. That's a serious defect waiting to happen.
Design guidelines inform us that a finalizer isn't necessary if your object implements IDisposable
, but if you have a finalizer you should implement IDisposable
to allow deterministic cleanup of your class.
Most of the time you should be able to get away with IDisposable
to clean up resources. You should only need a finalizer when your object holds onto unmanaged resources and you need to guarantee those resources are cleaned up.
Note: Sometimes coders will add a finalizer to debug builds of their own IDisposable
classes in order to test that code has disposed their IDisposable
object properly.
public void Dispose() // Implement IDisposable
{
Dispose(true);
#if DEBUG
GC.SuppressFinalize(this);
#endif
}
#if DEBUG
~MyClass() // the finalizer
{
Dispose(false);
}
#endif
protected virtual
for this reason, and follows what is called the NVPI pattern (Non Virtual Public Interface). Just make sure you document how subclasses should implement IDisposable and you're set. –
Olympian IDisposable
is not sealed
, then it should include the call to GC.SuppressFinalize(this)
even if it does not include a user-defined finalizer. This is necessary to ensure proper semantics for derived types that add a user-defined finalizer but only override the protected Dispose(bool)
method. –
Montano sealed
as mentioned by @SamHarwell is important, for the derived classes. CodeAnalysis results in ca1816+ca1063 when class is not sealed, but sealed classes are fine without SuppressFinalize
. –
Fuegian SupressFinalize
tells the system that whatever work would have been done in the finalizer has already been done, so the finalizer doesn't need to be called. From the .NET docs:
Objects that implement the IDisposable interface can call this method from the IDisposable.Dispose method to prevent the garbage collector from calling Object.Finalize on an object that does not require it.
In general, most any Dispose()
method should be able to call GC.SupressFinalize()
, because it should clean up everything that would be cleaned up in the finalizer.
SupressFinalize
is just something that provides an optimization that allows the system to not bother queuing the object to the finalizer thread. A properly written Dispose()
/finalizer should work properly with or without a call to GC.SupressFinalize()
.
SupressFinalise
is recommended, these days (2022/C# 10+)? –
Barabarabarabas Dispose(true);
GC.SuppressFinalize(this);
If object has finalizer, .net put a reference in finalization queue.
Since we have call Dispose(true)
, it clear object, so we don't need finalization queue to do this job.
So call GC.SuppressFinalize(this)
remove reference in finalization queue.
If a class, or anything derived from it, might hold the last live reference to an object with a finalizer, then either GC.SuppressFinalize(this)
or GC.KeepAlive(this)
should be called on the object after any operation that might be adversely affected by that finalizer, thus ensuring that the finalizer won't run until after that operation is complete.
The cost of GC.KeepAlive()
and GC.SuppressFinalize(this)
are essentially the same in any class that doesn't have a finalizer, and classes that do have finalizers should generally call GC.SuppressFinalize(this)
, so using the latter function as the last step of Dispose()
may not always be necessary, but it won't be wrong.
That method must be called on the Dispose
method of objects that implements the IDisposable
, in this way the GC wouldn't call the finalizer another time if someones calls the Dispose
method.
© 2022 - 2024 — McMap. All rights reserved.