Skip to main content

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

Popular posts from this blog

C# Snippet - Shuffling a Dictionary [Beginner]

Randomizing something can be a daunting task, especially with all the algorithms out there. However, sometimes you just need to shuffle things up, in a simple, yet effective manner. Today we are going to take a quick look at an easy and simple way to randomize a dictionary, which is most likely something that you may be using in a complex application. The tricky thing about ordering dictionaries is that...well they are not ordered to begin with. Typically they are a chaotic collection of key/value pairs. There is no first element or last element, just elements. This is why it is a little tricky to randomize them. Before we get started, we need to build a quick dictionary. For this tutorial, we will be doing an extremely simple string/int dictionary, but rest assured the steps we take can be used for any kind of dictionary you can come up with, no matter what object types you use. Dictionary < String , int > origin = new Dictionary < string , int >();

C# Snippet - The Many Uses Of The Using Keyword [Beginner]

What is the first thing that pops into your mind when you think of the using keyword for C#? Probably those lines that always appear at the top of C# code files - the lines that import types from other namespaces into your code. But while that is the most common use of the using keyword, it is not the only one. Today we are going to take a look at the different uses of the using keyword and what they are useful for. The Using Directive There are two main categories of use for the using keyword - as a "Using Directive" and as a "Using Statement". The lines at the top of a C# file are directives, but that is not the only place they can go. They can also go inside of a namespace block, but they have to be before any other elements declared in the namespace (i.e., you can't add a using statement after a class declaration). Namespace Importing This is by far the most common use of the keyword - it is rare that you see a C# file that does not h

C# WPF Printing Part 2 - Pagination [Intermediate]

About two weeks ago, we had a tutorial here at SOTC on the basics of printing in WPF . It covered the standard stuff, like popping the print dialog, and what you needed to do to print visuals (both created in XAML and on the fly). But really, that's barely scratching the surface - any decent printing system in pretty much any application needs to be able to do a lot more than that. So today, we are going to take one more baby step forward into the world of printing - we are going to take a look at pagination. The main class that we will need to do pagination is the DocumentPaginator . I mentioned this class very briefly in the previous tutorial, but only in the context of the printing methods on PrintDialog , PrintVisual (which we focused on last time) and PrintDocument (which we will be focusing on today). This PrintDocument function takes a DocumentPaginator to print - and this is why we need to create one. Unfortunately, making a DocumentPaginator is not as easy as