Automatic Non-Deterministic Finalisation

The automatic mechanism cannot be deterministic, because it must rely on on the GC to discover whether the object is referenced or not. At times this behaviour is a show stopper. because temporary “resource leaks” or holding a shared resource locked for slightly longer than necessary might be unacceptable in an application. At others, it’s perfectly acceptable. I will focus on the scenarios where it is.

Any type can override protected Finilize method defined by System.Object to indicate that it required automatic finalisation. However the C# syntax for requesting automatic finalisation on a class A is to implement method ~A(). This method is called finiliser a must be invoked when the object is destroyed.

Incidentally any type can have a finalizer, even the value types. However the finalizer on the value type object will never be invoked.

When an object with finiliser is created, a reference to it is added to a special queue – called finalisation queue.

It should be noted that like any collection this queue requires a synchronisation, so creating many objects with finalizers from different threads will theoretically affect the performance.

When the object gets unreferenced in the application, only the finalisation queue will have a reference to that object. The GC then moves that reference to f-reachable queue. This queue is considered a root to that object, so the object cannot be collected just yet.

It’s worth pointing out that object’s finiliser doesn’t run together with GC, instead a special thread called finilizer is invoking the finalisation method on each of the objects. Once the finalizer method has been run it is then removed from the f-reachable queue, leaving it without any reference to it – so during the next iteration, the GC is free to reclaim memory from the object.

If the finalise method throws an exception, that exception is simply ignored.

Pitfalls of Non-Deterministic Finalisation

It should be obvious to anyone by now that this model carries significant performance penalties:

  1. Object with finalisers are guaranteed to reach at least Generation 1
  2. They are more expensive to allocated, since they have to be added to finalisation queue. Even more expensive if those objects are added from different threads and synchronisation is required
  3. Pressure on the finalizer thread might cause memory leaks, if the rate of allocation is greater that the rate at which finilizer thread is able to run.

What it means

Deterministic memory collection should be used in favour of finilizers. One of such patterns in .NET is IDisposable interface. Finalisers should be used as a last resort, in case the developer forgets to deterministically clean up after the object

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: