374

In .NET, under which circumstances should I use GC.SuppressFinalize()?

What advantage(s) does using this method give me?

denfromufa
  • 5,610
  • 13
  • 81
  • 138
Sam Saffron
  • 128,308
  • 78
  • 326
  • 506
  • I have seen a few questions about finalizers and IDisposable, stackoverflow should also have something about GC.SupressFinalize and weak references – Sam Saffron Sep 29 '08 at 22:42
  • I don't think weak references do much of anything regarding finalizers - maybe you should post a more direct question about them. – Michael Burr Sep 30 '08 at 15:41
  • Yerp I was meaning to post a separate question about weak refs, all of this can tie together when you build object pools. Also I should ask a question about object revival ala ReRegisterForFinalize – Sam Saffron Sep 30 '08 at 22:50

5 Answers5

380

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
Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
Robert Paulson
  • 17,603
  • 5
  • 34
  • 53
  • I agree with your code but I would put an assert into the debug version...and if the resource being disposed was expensive, I would leave the finalizer in the release verion. – Jack Bolding Sep 30 '08 at 00:07
  • 2
    In the first code snippet I'm just posting what the recommended IDisposable + finalizer pattern looks like. Debugging code is good, but it can be distracting. .. I can only recommend avoiding finalizers except for classes that have unmanaged resources. Writing safe finalizer code is non-trivial. – Robert Paulson Sep 30 '08 at 00:18
  • Can I use disposing pattern in a base class and extend it among others one? – Eduardo Xavier Nov 12 '09 at 13:27
  • @Eduardo, yes you can absolutely. The recommended Dispose method is `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. – Robert Paulson Nov 13 '09 at 04:03
  • 3
    Hi, Why do we need to call dispose with false as parameter from finalizer? What if the dispose never got called and then it wont dispose? What if we just check for whether the object has been disposed or not and do the actual cleanup. – Dreamer Jun 01 '12 at 16:52
  • In other words, do we really need disposing parameter in protected virtual void Dispose(bool disposing)? can anyone please explain? i think the variable disposed is good enough. – Dreamer Jun 01 '12 at 16:53
  • 6
    @Dreamer - it depends on your implementation. In general you want to know if Dispose is being called by the finalizer versus the IDisposable.Dispose() implementation. If called from the finalizer, you must assume private references are no longer valid, and you really can't do much. If however called from IDisposable.Dispose(), you know that references are still valid. – Robert Paulson Jun 18 '12 at 23:47
  • 60
    If the class implementing `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. – Sam Harwell Mar 01 '13 at 20:12
  • Thanks @280Z28 - do you have any further references that others might find helpful? – Robert Paulson Sep 04 '13 at 10:45
  • @Robert - if private references aren't valid, what *can* I do that is likely to be of any use? It seems unusual to have a "pattern" in common use that doesn't appear to have common benefits. – bacar Aug 31 '16 at 22:22
  • @bacar Managed references are assumed to be invalid at that point, but unmanaged resources can still be freed. See https://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.100).aspx - I'll update the answer – Robert Paulson Nov 01 '16 at 04:24
  • 4
    Not being `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`. – dashesy Dec 13 '19 at 19:22
52

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().

Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • 1
    *A properly written Dispose()/finalizer should work properly with or without a call to GC.SupressFinalize()* - Out of interest, is there any reason why it's recommended that `SupressFinalise` is recommended, these days (2022/C# 10+)? – Paul Dec 08 '22 at 11:33
6
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.

hlovdal
  • 26,565
  • 10
  • 94
  • 165
Max CHien
  • 133
  • 1
  • 8
  • 2
    IMO this is an anti-pattern. At best it falls into the premature optimization bracket. Is the finalisation queue a bottle neck in your system, unlikely. Does doing this wrong have performance issues, yes. So the "cure" is worse than the disease. – Liam Apr 25 '22 at 09:30
2

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.

supercat
  • 77,689
  • 9
  • 166
  • 211
-1

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.

See: GC.SuppressFinalize(Object) Method - Microsoft Docs

Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
albertein
  • 26,396
  • 5
  • 54
  • 57
  • 10
    I think "Must" is wrong - not even "should" - It's just that in some scenarios, you can eliminate the overhead of queueing/finalizing the object. – Basic Sep 30 '10 at 02:05