#931 – Objects with Finalizers Take Longer to Garbage Collect

The purpose of the garbage collector is to discover objects on the managed heap that are no longer reachable and to reclaim the memory occupied by these objects.

Once an object is discovered to be no longer reachable, the garbage collector checks to see if the object has a finalizer.  If the object doesn’t have a finalizer, it is marked for collection and its memory is reclaimed by the garbage collector.

If an object has a finalizer, it will not be marked for garbage collection, but instead be marked for finalization.  It will not get garbage collected during the current pass of the garbage collector.  Instead, its finalizer will be run at some point after garbage collection finishes.  It will then be eligible for collection during the next pass of the garbage collector.

Reclaiming memory for objects with finalizers therefore requires at least two passes of the garbage collector.

Advertisement

#879 – Unhandled Exceptions in Finalizers

Like other unhandled exceptions, an exception that is thrown from a finalizer and not handled will cause your application to terminate.

~Dog()
{
    Console.WriteLine(
       "Dog finalizer is running.  I'll throw an exception and your app will terminate");
    throw new Exception("Dang it");
}
Dog d = new Dog("Kirby", 15);
d.Bark();

d = null;
GC.Collect();

879-001

#832 – The Sequence in Which Finalizers Are Called

When you implement a finalizer, using the destructor syntax, the finalizer needs to always call the finalizer of its base class.  The C# compiler will automatically take care of this, invoking the finalizer of the base class within a finally block to ensure that it gets called.

Because the call to the finalizer of the base class occurs within a finally block, it will get called after all of the code within the derived class’ finalizer has executed.  This means that the sequence in which the finalizers are called is from the most derived class up the inheritance chain.

For example, if Terrier inherits from Dog, code in the Terrier’s finalizer will execute before code in the Dog’s finalizer.

 

 

#739 – Avoid Accessing an Object After Its Been Finalized

A finalizer should not create a new reference to the object being finalized.  Below is an example where doing this leads to the ability to reference the object after it’s been finalized.

This is an example of questionable code–in general, it’s dangerous to reconstitute an object after it’s been finalized.

In the Dog class, we save a reference to the object being finalized.

    public class Dog
    {
        public static Dog KeepDogRef;

        public string Name { get; set; }

        public Dog(string name)
        {
            Name = name;
        }

        ~Dog()
        {
            Console.WriteLine("Dog destructor for " + Name + " called");
            Dog.KeepDogRef = this;
        }

        public void Bark()
        {
            Console.WriteLine(Name + " : Woof");
        }
    }

In main program, we reconstitute a Dog object after it’s been finalized.

            Dog dog = new Dog("Bowser");

            WeakReference dogRef = new WeakReference(dog);

            // Unref Bowser
            dog = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();

            // Bowser is gone
            Console.WriteLine(string.Format("Object still alive: {0}", dogRef.IsAlive));

            // Hey, Bowser is alive again!
            Dog newRef = Dog.KeepDogRef;
            newRef.Bark();

739-001

#737 – When to Implement a Finalizer

In C#, you implement a finalizer using the destructor (~) syntax.  The finalizer is called by the system when the object is being destroyed.

In general, you rarely need to implement a finalizer.  Rules of thumb for implementing a finalizer include:

  • Implement a finalizer only when the object has unmanaged resources to clean up (e.g. file handles)
  • Do not implement a finalizer if you don’t have unmanaged resources to clean up
  • The finalizer should release all of the object’s unmanaged resources
  • Implement the finalizer as part of the dispose pattern, which allows for deterministic destruction
  • The finalizer should only concern itself with cleanup of objects owned within the class where it is defined
  • The finalizer should avoid side-effects and only include cleanup code
  • The finalizer should not add references to any objects, including a reference to the finalizer’s own object
  • The finalizer should not call methods in any other objects

#672 – An Exception Thrown From a Finalizer Will Be Treated as an Unhandled Exception

If an exception originates in a finalizer in C# and is not handled within the body of the finalizer, the exception will be treated by the application as an unhandled exception.  If you have no mechanism for dealing with unhandled exceptions, this will lead to a crash.

In the example below, the exception originating in the Dog finalizer is not caught within the Main method.

        static void Main()
        {
            try
            {
                Dog d = new Dog();
                d = null;

                GC.Collect();
                GC.WaitForPendingFinalizers();

                Console.WriteLine("I made it to the end of the program");
                Console.ReadLine();
            }
            catch (Exception xx)
            {
                Console.WriteLine(string.Format("Hey, I caught an exception! {0}", xx.ToString()));
            }
    public class Dog
    {
        public Dog()
        {
            Console.WriteLine("Dog constructor");
        }

        ~Dog()
        {
            Console.WriteLine("Dog finalizer running");
            throw new Exception("** Exception from Dog finalizer **");
        }
    }

#646 – Value Types Don’t Have Finalizers

In .NET, you override the Object.Finalize method to dispose of any unmanaged resources when the object is being garbage collected.  In C#, you write this finalizer using the destructor (~) syntax.  You can also implement the Dispose pattern to allow users of your object to deterministically dispose of  resources.

You cannot implement a finalizer or the dispose pattern for a value type.  A finalizer makes no sense for a value type because value typed objects are not garbage collected–they simply die when they go out of scope.

Since the finalizer and the dispose pattern exist for the purpose of releasing unmanaged resources, and you can’t implement either for a value type, you should avoid using unmanaged resources in value types.  A user would have to explicitly call some method to do the cleanup and there is no guarantee that they would remember to call the method.

#428 – A Finalizer Should Always Call the Finalizer of Its Base Class

An implementation of Object.Finalize for a particular class in .NET should always call the Finalize method of its base class.  In the case of C#, you can’t explicitly override Finalize, but you provide a finalizer using the destructor (~) syntax.  When you do this, the compiler will automatically add code to ensure that your destructor calls Finalize in the base class.

In the example below, I write a simple destructor for the Dog class.  We can see in the IL that the Finalize method has been overridden and that it calls System.Object.Finalize in the finally clause.

        ~Dog()
        {
            Trace.WriteLine("This dog is on the way out..");
        }

#427 – Finalizer Gotchas

The idea of the finalizer in .NET is that you can override the Object.Finalize method, called by the garbage collector when it’s releasing memory for an object, and you can do any required cleanup of unmanaged resources.

There are several things to keep in mind if you want to write a finalizer (done in C# using the destructor syntax):

  • You can’t predict when your finalizer is called
  • The finalizer might never get called at all
  • The order that finalizers are called in is unpredictable.  You therefore can’t assume that any other managed object that your object references still exists, or is in a known state.
  • Garbage collection will take longer if you have objects with finalizers

 

#426 – Use a Destructor to Free Unmanaged Resources

When an object is no longer referenced by other objects, its memory may be reclaimed by the garbage collector in the CLR.  If you have any unmanaged resources that you need to clean up explicitly, you can implement a finalizer for your class.

A finalizer is the implementation of the Object.Finalize method for your class, which the garbage collector calls when it’s ready to release memory for an object.  In C#, you implement a finalizer using the destructor syntax–a method defined as a tilde (~), followed by the name of the class.

    public class Dog
    {
        ~Dog()
        {
            Trace.WriteLine("This dog is on the way out..");
        }

When you look at the IL for this class, you’ll see that the compiler has overridden the Finalize method.

You’ll notice that this method is now called when the garbage collector is releasing the object.