TL;DR – Avoid Finalizers when possible!
Today i want to talk about the Finalization of objects in the .NET framework.
I find this subject important because one simple mistake in your Finalizer may get you in to a lot of trouble and may hang or even crash your process.
One of the most important milestones in the history of programming languages was the invention of managed code. In the early days, when developers mostly used low level languages (like C or C++), those languages were compiled in to machine code that the computer can understand. When executed, the code instructions were fed directly to the CPU for processing. No middle-man involved.
There were lots of advantages mainly in a shape of performance, because it was possible for the developers to write very performant code and manage the memory of the process.
While it was possible, it was also very burdensome, it was really hard and it took a lot of time to produce a robust, tested component in those languages. There were too many pitfalls.
As a natural turn of events, and as the computer hardware became cheaper, managed languages started to appear. Those languages gave up some of the performance abilities in favor of development speed. They are called managed because there is another code that manages your code, and most importantly the other code is managing your memory, which used to cause immense amounts of headache to developers in past years.
When compiled, the managed language was not compiled to a machine understandable instructions but rather to some kind of intermediate code that the managing framework can understand. Examples of managed languages are of course Java, C#, VB.NET etc…
So what is a Finalizer?
While the managed code platform like the CLR (or the JVM for java) will manage your program’s memory for you, it will do that only for your managed code! Why is this important? Well, in case you need to use some native (unmanaged) resources from your operating system, for example holding a file handle, freeing-up that memory is not the responsibility of your managed code platform. That is where the Finalizer methods code in to play.
Finalizer in .NET is just a constructor prefixed with a tilde (~), and the Garbage Collector will run this constructor (that is actually called a Destructor) for you hoping that the code you have placed there is tested and free of bugs.
Lets assume your code is referencing a native object, for example a file handle. When the Garbage Collector runs, it will free the referencing variable in your class, but it will not be able to clean the created file handle because it is not part of your managed code. That way your program will have a memory leak.
Finalizer is the place where you can clean-up unmanaged resources, release handles, close DB connections, dispose Socket connections etc.
How Finalizer works:
Every .NET object that has a finalizer will be put on the Finalization Queue. When GC inspects that object and decides that it needs to be cleaned up, the object will be moved to the FReachable Queue. In every .NET process there is a dedicated thread that executes finalizers on every object in the FReachable Queue.
Imagine a situation where your Finalizer has a hang bug, what will happen then? Well, your finalization thread will freeze and will not be executing Finalizers of any other object. This will guaranty an unstable behavior and even crash your process after the memory runs out.
In fact, any exception in your Finalizer will impact the finalization thread, and this is of course not a good thing to do.
If you have to clean-up some unmanaged resources that are used in your class, you should do that explicitly in your code by implementing the Disposable design pattern.
If you are angry, mad or just happy about this post and want to share it with me – leave a comment.