C# Tutorial - Object Finalizers [Advanced]


Recently, in a tutorial about WeakReferences in C#, we talked a bit about garbage collection and how the garbage collector works in .NET. I figured since we already started addressing that stuff, there is no reason not to delve deeper. And so, today we are going to take a look at how object finalizers work in C#.

What is an object finalizer? I'm glad you asked! They are essentially the cleanup functions for classes - when an object is collected by the garbage collector in .NET, the finalizer gets run, hopefully cleaning up any unmanaged resources that object may have been holding on to (file references, window handles, network sockets, etc...). An object finalizer is in may ways similar to the C++ destructor, but unlike in C++, a programmer can never call a finalizer directly (in C++, there is the delete operator, and .NET has no such equivalent).

So, first, lets take a look at how to write a finalizer, and then we can delve into the details on when they are run and other caveats.
class ClassWithFinalizer
{
  System.Timers.Timer _SillyTimer;

  public ClassWithFinalizer()
  {
    _SillyTimer = new System.Timers.Timer(100);
    _SillyTimer.Elapsed += 
        (a, b) => Console.WriteLine("Still Alive!");
    _SillyTimer.Start();
  }

  //Finalizer
  ~ClassWithFinalizer()
  {
    _SillyTimer.Stop();
    _SillyTimer.Dispose();
    Console.WriteLine("You Killed Me!!");
  }
}
 
The class in the code block above has a finalizer, and probably by looking at the code you have already figured out the syntax for writing your own. To write a finalizer method, all you do is create a method with the same name as the class (kind of like how you declare a constructor) and you prefix it with a "\~". The method takes no arguments, and it does not use the public/private scoping keywords (because a finalizer never gets called explicitly in code anyway).

So what is the above class doing, anyway? Well, its kind of silly, but it shows off the finalizer pretty well. In the constructor we create a timer, and set it so that every 100 milliseconds it prints out the statement "Still Alive!". So when we create this class, "Still Alive!" should print to the console window until the program closes....or at least that is what it would do if there wasn't a finalizer.

When this object gets garbage collected, it stops and disposes the timer, and prints out the final message "You Killed Me!!". Below is some code that causes this behavior to happen, and the corresponding output:
static void Main(string[] args)
{
  new ClassWithFinalizer();
  System.Threading.Thread.Sleep(500);
  GC.Collect();
}

Still Alive!
Still Alive!
Still Alive!
Still Alive!
You Killed Me!!
 
At the start of the main method, we create an instance of ClassWithFinalizer, but we don't assign the resulting reference to anything. That means that we created the object, but no one is referencing it, so at any point the garbage collector can come along and destroy it. We then sleep the main thread for a bit, possibly letting the instance of ClassWithFinalizer print out "Still Alive" a few times, and then we force a garbage collection by calling GC.Collect(). The garbage collection notices that no one is referencing the instance of ClassWithFinalizer, and so collects it, and in the process executes the finalizer, killing the timer, and printing out the final message of "You Killed Me!!"

What if we didn't have the explicit call to GC.Collect(), and the program just sat there? Well, lets take that line out (and add a Console.Read() to cause the program to sit there):
static void Main(string[] args)
{
  new ClassWithFinalizer();
  Console.Read();
}

Still Alive!
Still Alive!
Still Alive!
Still Alive!
Still Alive!
Still Alive!
Still Alive!
Still Alive!
Still Alive!
Still Alive!
...
...
...
You Killed Me!!
 
Who knows how long it would be till the garbage collector finally tried to collect that instance of ClassWithFinalizer? It is quite possible it wouldn't happen until the program closed.

So does that all make sense? Good, cause it is about to become less clear. One of the main caveats of finalizers in .NET is that there are no guarantees about when the finalizer for an object will actually get run. Unlike in C++, where the destructor gets called as soon as an object goes out of scope (and if that's not enough the delete operator can trigger the destructor explicitly), finalizers in C# are not deterministic. A C# finalizer will be called at some point between when the object is last used and the ending of the program - and you as a programmer don't know any more than that.

Hey, and if you look even deeper, it gets yet more complicated - finalizers are not run immediately when the garbage collector gets around to realizing an object can be collected. The garbage collector sees that the object has a finalizer and so adds it to the finalization queue (or f-reachable queue). Eventually, the finalizer method gets run, and then when the garabge collector realizes that, it finally frees the object's memory. So using finalizers can actually delay the real collection on an object for some number of garbage collection cycles.

In a simple example like the one above, everything works as expected. But when you get into bigger programs, this no-deterministic method of finalization can get in the way. The creators of .NET realized this, and so created the Disposable pattern and the using statement, which gives programmers the ability to do much more deterministic object disposal. That, however, is a discussion long enough for another tutorial all on its own.

Comments