89

I am studying how garbage collector works in c#. I am confused over the use of Destructor, Dispose and Finalize methods.

As per my research and understandings, having a Destructor method within my class will tell the garbage collector to perform the garbage collection in the way mentioned in the destructor method which cannot be called explicitly on the instances of the class.

The Dispose method is meant to provide the user to control the garbage collection. The Finalize method frees the resources used by the class, but not the object itself.

I am not sure if I understand it the right way. Please clarify the doubts. Any further links or guides are welcome.

gonzobrains
  • 7,856
  • 14
  • 81
  • 132
Victor Mukherjee
  • 10,487
  • 16
  • 54
  • 97

2 Answers2

77

Destructor implicitly calls the Finalize method, they are technically the same. Dispose is available with objects that implement the IDisposable interface.

You may see : Destructors C# - MSDN

The destructor implicitly calls Finalize on the base class of the object.

Example from the same link:

class Car
{
    ~Car()  // destructor
    {
        // cleanup statements...
    }
}

The Destructor's code is implicitly translated to the following code:

protected override void Finalize()
{
    try
    {
        // Cleanup statements...
    }
    finally
    {
        base.Finalize();
    }
}

Your understanding for the Destructor is right:

From MSDN

The programmer has no control over when the destructor is called because this is determined by the garbage collector. The garbage collector checks for objects that are no longer being used by the application. If it considers an object eligible for destruction, it calls the destructor (if any) and reclaims the memory used to store the object. Destructors are also called when the program exits. It is possible to force garbage collection by calling Collect, but most of the time, this should be avoided because it may create performance issues.

Humberto Gomes
  • 139
  • 1
  • 10
Habib
  • 219,104
  • 29
  • 407
  • 436
  • How forcing garbage collection by calling `Collect()` may method create performance issues? – Destructor Apr 13 '16 at 13:13
  • @Destructor, the mark phase of GC uses the DFS which has a linear time and space complexities with respect to the total number of objects in an app. So, it is better to leave to GC to decide when to use so much resources and do not try to utilize them yourself. – manymanymore May 04 '21 at 08:25
  • @Destructor I am sure you don't need to see this, but for the convenience of others seeking answers I find this chart quite instructive - together with pondering about consequences of too frequent and sub-optimal calling GC.Collect() [link](https://miro.medium.com/max/1400/1*bJpH4RyFIWR4mJrXo9DpYA.png) – Sold Out Aug 24 '22 at 09:19
  • @SoldOut To enhance the info, I provide a more .net CLR specific link, where the most crucial info is (wrt to the discussed) this: One of the GC phases is memoryre-organisation => inevitable pause of app threads. "* A relocating phase that updates the references to the objects that will be compacted." [Source](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals) – Sold Out Aug 24 '22 at 10:00
64

In C# terms, a destructor and finalizer are basically interchangeable concepts, and should be used to release unmanaged resources when a type is collected, for example external handles. It is very rare that you need to write a finalizer.

The problem with that is that GC is non-deterministic, so the Dispose() method (via IDisposable) makes it possible to support deterministic cleanup. This is unrelated to garbage collection, and allows the caller to release any resources sooner. It is also suitable for use with managed resources (in addition to unmanaged), for example if you have a type that encapsulates (say) a database connection, you might want disposing of the type to release the connection too.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • so what I feel is that the Destructor method should contain only the code which must be executed before its destruction, the Finalize method will mostly be thereafter inherited from the super class. – Victor Mukherjee Dec 21 '12 at 10:51
  • 3
    @VictorMukherjee again, they (destructor and finalizer) are interchangeable. It is the `Dispose()` that would be called *before* destruction, but that is not referred to as either destructor or finalizer – Marc Gravell Dec 21 '12 at 10:58
  • Hi Marc, is it right in thinking that GC is mostly deterministic, just that the rules aren't commonly known? I'm no expert, always learning, I was wondering if your comment was just broadly speaking in the context of finalizers v.s dispose? Or is it very much nondeterministic (albeit that's perhaps another question for another day)? – Alex KeySmith Sep 14 '19 at 21:59
  • 1
    @AlexKeySmith I would have to say the latter, in that it is governed by timing, CPU activity, and external factors like external memory – Marc Gravell Sep 15 '19 at 12:43
  • Thanks Marc, that's very useful; Ah so even if the underlying rules are deterministic it's governed by much outside of the control of the app it's effectively non-deterministic. Thanks for the insight! – Alex KeySmith Sep 15 '19 at 18:21