Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why should we call SuppressFinalize when we don't have a destructor

I have few Question for which I am not able to get a proper answer .

1) Why should we call SuppressFinalize in the Dispose function when we don't have a destructor .

2) Dispose and finalize are used for freeing resources before the object is garbage collected. Whether it is managed or unmanaged resource we need to free it , then why we need a condition inside the dispose function , saying pass 'true' when we call this overridden function from IDisposable:Dispose and pass false when called from a finalize.

See the below code I copied from net.

class Test : IDisposable    {      private bool isDisposed = false;       ~Test()      {        Dispose(false);      }       protected void Dispose(bool disposing)      {        if (disposing)        {          // Code to dispose the managed resources of the class        }        // Code to dispose the un-managed resources of the class         isDisposed = true;      }       public void Dispose()      {        Dispose(true);        GC.SuppressFinalize(this);      }    } 

what if I remove the boolean protected Dispose function and implement the as below.

   class Test : IDisposable    {      private bool isDisposed = false;       ~Test()      {        Dispose();      }        public void Dispose()      {       // Code to dispose the managed resources of the class       // Code to dispose the un-managed resources of the class       isDisposed = true;        // Call this since we have a destructor . what if , if we don't have one         GC.SuppressFinalize(this);      }    }        
like image 731
somaraj Avatar asked Apr 09 '10 06:04

somaraj


People also ask

Why should one call GC SuppressFinalize when implementing Dispose method?

Dispose should call GC. SuppressFinalize so the garbage collector doesn't call the finalizer of the object. To prevent derived types with finalizers from having to reimplement IDisposable and to call it, unsealed types without finalizers should still call GC.

What is SuppressFinalize?

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.

Why we need to implement Dispose method while we have option to implement destructor?

It is always recommended to use Dispose method to clean unmanaged resources. You should not implement the Finalize method until it is extremely necessary. At runtime C#, C++ destructors are automatically converted to Finalize method.

What is difference between destructor and finalize?

Destructor implicitly calls the Finalize method, they are technically the same. Dispose is available with objects that implement the IDisposable interface. The destructor implicitly calls Finalize on the base class of the object.


2 Answers

I'm going out on a limb here, but... most people don't need the full-blown dispose pattern. It's designed to be solid in the face of having direct access to unmanaged resources (usually via IntPtr) and in the face of inheritance. Most of the time, neither of these is actually required.

If you're just holding a reference to something else which implements IDisposable, you almost certainly don't need a finalizer - whatever holds the resource directly is responsible for dealing with that. You can make do with something like this:

public sealed class Foo : IDisposable {     private bool disposed;     private FileStream stream;      // Other code      public void Dispose()     {         if (disposed)         {             return;         }         stream.Dispose();         disposed = true;     } } 

Note that this isn't thread-safe, but that probably won't be a problem.

By not having to worry about the possibility of subclasses holding resources directly, you don't need to suppress the finalizer (because there isn't one) - and you don't need to provide a way of subclasses customising the disposal either. Life is simpler without inheritance.

If you do need to allow uncontrolled inheritance (i.e. you're not willing to bet that subclasses will have very particular needs) then you need to go for the full pattern.

Note that with SafeHandle from .NET 2.0, it's even rarer that you need your own finalizer than it was in .NET 1.1.


To address your point about why there's a disposing flag in the first place: if you're running within a finalizer, other objects you refer to may already have been finalized. You should let them clean up themselves, and you should only clean up the resources you directly own.

like image 123
Jon Skeet Avatar answered Oct 03 '22 01:10

Jon Skeet


Here are the main facts

1) Object.Finalize is what your class overrides when it has a Finalizer. the ~TypeName() destructor method is just shorthand for 'override Finalize()' etc

2) You call GC.SuppressFinalize if you are disposing of resources in your Dispose method before finalization (i.e. when coming out of a using block etc). If you do not have a Finalizer, then you do not need to do this. If you have a Finalizer, this ensures that the object is taken off of the Finalization queue (so we dont dispose of stuff twice as the Finalizer usually calls the Dispose method as well)

3) You implement a Finalizer as a 'fail safe' mechanism. Finalizers are guaranteed to run (as long as the CLR isnt aborted), so they allow you to make sure code gets cleaned up in the event that the Dispose method was not called (maybe the programmer forgot to create the instance within a 'using' block etc.

4) Finalizers are expensive as Types that have finalizers cant be garbage collected in a Generation-0 collection (the most efficient), and are promoted to Generation-1 with a reference to them on the F-Reachable queue, so that they represent a GC root. it's not until the GC performs a Generation-1 collection that the finalizer gets called, and the resources are released - so implement finalizers only when very important - and make sure that objects that require Finalization are as small as possible - because all objects that can be reached by your finalizable object will be promoted to Generation-1 also.

like image 22
Dean Chalk Avatar answered Oct 02 '22 23:10

Dean Chalk