1

This is a follow up question to this question:

Finalize/Dispose pattern in C#

So I understand that if I'm creating a class that uses unmanaged resources, I should dispose them. The answer in the linked question says that the finalizer disposes of the unmanaged resources. However, the Dispose(Boolean) method is also disposing of unmanaged resources:

protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // get rid of managed resources
        }   
        // get rid of unmanaged resources
    } 

So what is the difference between the disposal of the finalizer and the disposal of the dispose method?

Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
CodeMonkey
  • 11,196
  • 30
  • 112
  • 203
  • As you can see in the accepted answer the finalizer - if existing .- would usually **call** your `Dispose`-method with the flag being `false`. – MakePeaceGreatAgain Jan 22 '19 at 08:33
  • 1
    It is Garbage Collector that's collect garbage and call finalizer. Please, note that there's no guarantee that garbage will be collected at all (or if it will be, *when* it'll be done). On the contrary `Dispose` is called *manually* (usually, when leaving `using` scope). – Dmitry Bychenko Jan 22 '19 at 08:35
  • So the finalizer exist ONLY to call the Dispose method in case the user forgot to call it himself? – CodeMonkey Jan 22 '19 at 08:35
  • Yes, the finalizer exists to ensure that *unmanaged* resources are released when possible. An unreleased unmanaged resource can cause havoc - Imagine a file handle being incorrectly left open for the lifetime of an application. – Matthew Watson Jan 22 '19 at 08:37
  • I understand the consequence. I just thought that both the Dispose AND finalizer are doing something like Release(unmanagedObject) and didn't understand why. but if the implementation of a finalizer ALWAYS in case of this pattern be Dispose(false) then I understand it. Just to confirm - is it correct? – CodeMonkey Jan 22 '19 at 08:40
  • The key thing here is that the finalizer is only called if the Dispose() method is not called (or the Dispose() method forgets to call `GC.SuppressFinalize(this)`). So the finalizer needs to dispose the unmanaged resources somehow, and the Dispose() needs to dispose both the unmanaged AND the managed resources. This is what [the "Dispose pattern"](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose) covers. – Matthew Watson Jan 22 '19 at 08:43
  • which means that indeed in case of the dispose pattern, the implementation of a finalizer will ALWAYS be just a single line of Dispose(false)? – CodeMonkey Jan 22 '19 at 08:45
  • 1
    Yep, as long as you are following the Dispose() pattern, that would be true. – Matthew Watson Jan 22 '19 at 09:56

3 Answers3

3

The only reason you would use it (and its extremely controversial).

  1. A finalizer allows the clearing an object before it will be deleted by a garbage collector. (That's to say, The GC is responsible for calling it, and clearing the object from memory) If the developer forgot to call Dispose() method of an object, then it will be possible to free the unmanaged resources and thus, avoid the leak.

There are many reasons not to, and many ways to get it wrong. In short there is seldom a reason why you need to do this, or want to do it

TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • 1
    "A finalizer allows the clearing an object before it will be deleted by a garbage collector." Isn´t the finalizer called by the GC? – MakePeaceGreatAgain Jan 22 '19 at 08:35
  • @HimBromBeere The GC is responsible for calling it, and clearing the object from memory – TheGeneral Jan 22 '19 at 08:38
  • And the 1st reason among `15` not to is that releasing resource in finalizer aggravates the situation with resource leakage: it becomes *unstable*. – Dmitry Bychenko Jan 22 '19 at 08:39
  • @DmitryBychenko exactly, this is a choose your own adventure of how to potentially do something nasty – TheGeneral Jan 22 '19 at 08:39
  • When the GC is clearing an object that has a finalize method, will it just run the finalize method assuming the method will also clear the managed resources, or will it free the managed resources itself assuming the finalizer releases the unmanaged resourced ONLY? – CodeMonkey Jan 22 '19 at 08:42
  • A finalizer should never touch any managed resources. It's one of the "rules" of using a finalizer. Which is why in the Dispose pattern, a flag is used to guard the managed resources. – pinkfloydx33 Jan 22 '19 at 09:43
  • @pinkfloydx33 indeed, unfortunately I wrote this on my phone, and lost the will to add much more detail. In short there is really no good reason to use them that out weighs the bad – TheGeneral Jan 22 '19 at 09:49
  • @TheGeneral sorry, was meant as a comment towards OP – pinkfloydx33 Jan 22 '19 at 09:49
1

In addition to given answer: finalizer is is called by garbage collector when it runs.

So you can't rely on time of releasing unmanaged resources in finalizer! Because it is unknown.

Also, finalizer runs on another thread, so when garbage collection finishes, finalization may be still running! So there has to by another garbage collection, to completely get rid of an object.

So, first garbage collection call finalezrs, but object doesn't get collected (and also objects, that the object holds references to), it will be collected on the second garbage collection.

Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
  • When the GC is clearing an object that has a finalize method, will it just run the finalize method assuming the method will also clear the managed resources, or will it free the managed resources itself assuming the finalizer releases the unmanaged resourced ONLY? – CodeMonkey Jan 22 '19 at 08:47
  • @YonatanNir No, you need to write code to release unmanaged resources. You can do it whether in `Dispose` method or in finalizer. I prefer `Dispose` method, because it runs immediately after calling it. Finalizer gets called by garbage collector and time of this is unknown. – Michał Turczyn Jan 22 '19 at 08:49
  • That's not exactly what I asked. I asked if the GC will call the finalizer AND free it from the memory, or will the GC call ONLY the finalizer, because the GC will assume that the finalizer also takes care of the managed resources? – CodeMonkey Jan 22 '19 at 08:52
  • @YonatanNir GC will only call finalizer on first garbage collection. Finalizer is called on another thread, so garbage collection will finish without waiting for finalizers called. **Memory will be freed on second garbage collection** – Michał Turczyn Jan 22 '19 at 08:54
  • Turczyn OK so in the end it will do both, but not at the same time. Just for curiosity, how can the GC know that the finalizer has finished even if it waited for the 2nd time? – CodeMonkey Jan 22 '19 at 08:58
  • @YonatanNir Well, I don't know for sure. But I know you can call method: `GC.WaitForPendingFinalizers()` to make sure all finalizers are finished. [Documentation](https://learn.microsoft.com/pl-pl/dotnet/api/system.gc.waitforpendingfinalizers?view=netframework-4.7.2) – Michał Turczyn Jan 22 '19 at 09:04
  • Just one last question... In case of calling Dispose(true) - how exactly do you dispose of managed resources? Doesn't the GC suppose to do it? – CodeMonkey Jan 22 '19 at 09:05
  • @YonatanNir No. That's the whole point of imlpementing `Dispose` method. Assume your class have connection to database: `SqlConnection conn;`, somewhere you open it but you also need to close it, when you get rid of object. Then in your `Dispose` method you need to call `conn.Close()` method to release this unmanaged resource. – Michał Turczyn Jan 22 '19 at 09:07
  • I was now talking about the MANAGED resourced. The dispose pattern indicates you should override a Dispose(Boolean). The Boolean value if true, means disposing of the managed resources(like the code snippet in my question). So if they are managed, won't the GC do it? – CodeMonkey Jan 22 '19 at 09:12
  • @YonatanNir Ah, GC will get rid of managed resources, not `Dispose` method. – Michał Turczyn Jan 22 '19 at 09:13
  • Then again.. what is supposed to happen in case Dispose is called with the value of true? the snippet says it needs to dispose of MANAGED resources.. – CodeMonkey Jan 22 '19 at 09:17
  • @YonatanNir No, that's not the idea of `Dispose` method. It's only supposed to manage unamanged resources. Managed resources are taken care of by garbage collector. – Michał Turczyn Jan 22 '19 at 09:28
  • So why is there a Boolean argument to the dispose method? What do you think should happen in case of a true value or in case a false value? – CodeMonkey Jan 22 '19 at 09:33
  • @YonatanNir All needed answers can be found here: https://learn.microsoft.com/pl-pl/dotnet/standard/garbage-collection/implementing-dispose I also need to read this - very useful resource on this topic :) – Michał Turczyn Jan 22 '19 at 09:50
0

An object with finalizer goes through two phases of GC: First time, the finalizer is run and second time, the object is actually collected and the memory is freed. Apart from increasing the GC pressure and delaying the memory release back to pool, finalizers also have the feature of working with objects whose fields may not be in valid state. Also, throwing an exception on finalizer thread tears down the whole application instantly without any friendly information on what just happened.

This is why the Dispose pattern implementation always features the call to GC.SuppressFinalize which causes the finalizer not to run in case the object was already disposed and the GC can directly free the memory on first run.

Generally, using finalizers can be very complex and tricky if your application should survive critical exceptions such as out of memory or thread abort and subsequent AppDomain unloads - this is the case for applications such as SQL Server or IIS.

Long story short: Do not use finalizers unless you absolutely have to, and if you have to (e.g. using unmanaged resources), there's quite a bit of research awaiting you.

You can find more reading on this topic in the following blog posts:

Eric Lippert - When everything you know is wrong

Joe Duffy - Never write a finalizer again

Zdeněk Jelínek
  • 2,611
  • 1
  • 17
  • 23
  • The basic idea of this answer is good, but just to clarify your first sentence: first, the GC thread identifies that the object is finalizable garbage and the object is placed on the finalizer queue, which is a GC root. Then, after the finalizer thread runs, the object typically marks itself as not finalizable. Then, a later GC identifies the object as not-finalizable garbage and that memory becomes a hole in the GC heap which is compacted away. – Eric Lippert Jan 22 '19 at 18:02
  • The way you phrased it makes it sound like the GC thread runs the finalizers, but it does not. It just puts the objects on a queue for the finalizer thread to deal with later. – Eric Lippert Jan 22 '19 at 18:03