Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why .NET Object has method Finalize()?

I know that Finalize method is used by garbage collector to let object free up unmanaged resources. And from what I know, Object.Finalize is never called directly by GC (object is added to f-reachable queue during it's construction if it's type overrides the Finalize method by implementing finalizer).

Object.Finalize is only called from autogenerated finalizer code:

try
{
  //My class finalize implementation
}
finally
{
  base.Finalize(); // Here chain of base calls will eventually reach Object.Finalize/
}

So having an arbitrary class, derived from Object, wouldn't call Object.Finalize - you need finalizer for Object.Finalize to make sense and for most classes it doesn't make sense and is unused (not saying it's implementation is empty in fact).

Would it be too complex to check existence of Finalize method in a class without it overriding Object.Finalize, and generating root finalizer without try{}finally{base.Finalize()} call? Something similar to Add method for collection initializing - you don't have to implement any interface or override that method - just implement public void Add(item) method.

It would complicate C# compiler a bit, but make finalizer run slightly faster by removing one redundant call, and most importantly - make Object class easier to understand without having protected Finalize method with empty implementation while it doesn't need to finalize anything.

Also it might be possible to implement FinalizableObject class, derived from Object and make compiler derive all classes which have finalizer from that. It could implement IDisposable and make the disposing pattern, recommended by Microsoft reusable without need to implement it in every class. Actually I'm surprised such base class doesn't exist.

like image 410
Sasha Avatar asked Oct 11 '17 14:10

Sasha


People also ask

What is the purpose of the finalize () method?

The Finalize method is used to perform cleanup operations on unmanaged resources held by the current object before the object is destroyed. The method is protected and therefore is accessible only through this class or through a derived class.

Why Finalize method is protected in object class?

The finalize() method is a pre-defined method in the Object class and it is protected. The purpose of a finalize() method can be overridden for an object to include the cleanup code or to dispose of the system resources that can be done before the object is garbage collected.

Do all objects have a Finalize method?

Since the Object class contains the finalize method hence finalize method is available for every java class since Object is the superclass of all java classes. Since it is available for every java class, Garbage Collector can call the finalize() method on any java object.

Why do we need a finalize () method when garbage collection is there?

finalize() is called by the garbage collector on an object when garbage collection determines that there are no more references to the object. A subclass overrides the finalize method to dispose of system resources or to perform other cleanup.


2 Answers

Edit

The garbage collection does not call the child implementation of Object.Finalise unless the method is overridden. Why is it available to all objects? So that it can be overridden when needed but unless it is there is no performance impact. Looking at documentation here, it states;

The Object class provides no implementation for the Finalize method, and the garbage collector does not mark types derived from Object for finalization unless they override the Finalize method.

Notes on finalization

Quoting directly from Ben Watson's excellent book Writing High-Performance .NET Code as he explains far better than I ever could;

Never implement a finalizer unless it is required. Finalizers are code, triggered by the garbage collector to cleanup unmanaged resources. They are called from a single thread, one after the other, and only after the garbage collector declares the object dead after a collection. This means that if your class implements a finalizer, you are guaranteeing that it will stay in memory even after the collection that should have killed it. This decreases overall GC efficiency and ensures that your program will dedicate CPU resources to cleaning up your object.

If you do implement a finalizer, you must also implement the IDisposable interface to enable explicit cleanup, and call GC.SuppressFinalize(this) in the Dispose method to remove the object from the finalization queue. As long as you call Dispose before the next collection, then it will clean up the object properly without the need for the finalizer to run. The following example correctly demonstrates this pattern;

class Foo : IDisposable
{
    ~Foo()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            this.managedResource.Dispose();
        }
        // Cleanup unmanaged resource
        UnsafeClose(this.handle);
        // If the base class is IDisposable object, make sure you call:
        // base.Dispose();
    }
}

Note Some people think that finalizers are guaranteed to run. This is generally true, but not absolutely so. If a program is force-terminated then no more code runs and the process dies immediately. There is also a time limit to how long all of the finalizers are given on process shutdown. If your finalizer is at the end of the list, it may be skipped. Moreover, because finalizers execute sequentially, if another finalizer has an infinite loop bug in it, then no finalizers after it will ever run. While finalizers are not run on a GC thread, they are triggered by a GC so if you have no collections, the finalizers will not run. Therefore, you should not rely on finalizers to clean up state external to your process.

Microsoft has a good write up on finalizers and the Disposable pattern here

like image 78
DiskJunky Avatar answered Sep 17 '22 18:09

DiskJunky


The C# language destructor syntax obscures too much about what a finalizer really does. Perhaps best demonstrated with a sample program:

using System;

class Program {
    static void Main(string[] args) {
        var obj = new Example();
        obj = null;    // Avoid debugger extending its lifetime
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Console.ReadLine();
    }
}

class Base { ~Base() { Console.WriteLine("Base finalizer called"); } }
class Derived : Base { ~Derived() { Console.WriteLine("Derived finalizer called"); } }
class Example : Derived { }

Output:

Derived finalizer called
Base finalizer called

There are some noteworthy things about this behavior. The Example class itself does not have a finalizer, yet its base class finalizers are called anyway. That the Derived class finalizer is called before the Base class finalizer is not accidental. And note that the Derived class' finalizer has no call to base.Finalize(), even though the MSDN article for Object.Finalize() demands that it does, yet it is called anyway.

You may easily recognize this behavior, it is the way a virtual method behaves. One whose override calls the base method, like virtual method overrides commonly do. Which is otherwise exactly what it is inside the CLR, Finalize() is a plain virtual method like any other. The actual code generated by the C# compiler for the Derived class' destructor resembles this:

protected override Derived.Finalize() {
    try {
        Console.WriteLine("Derived finalizer called"); 
    }
    finally {
        base.Finalize();
    }
}

Not valid code, but the way it could be reverse-engineered from the MSIL. The C# syntax sugar ensures you can never forget to call the base finalizer and that it can't be aborted by a thread abort or AppDomain unload. The C# compiler does not otherwise help and auto-generate a finalizer for the Example class; the CLR does the necessary work of finding the finalizer of the most-derived class, traversing the method tables of the base classes until it finds one. And likewise helps in the class loader by setting a flag to indicate that Example has base classes with a finalizer so needs to be treated specially by the GC. The Base class finalizer calls Object.Finalize(), even though it doesn't do anything.

So key point is that Finalize() is actually a virtual method. It therefore needs a slot in the method table for Object so a derived class can override it. Whether it could have been done differently is pretty subjective. Certainly not easily and not without forcing every language implementation to special-case it.

like image 27
2 revs Avatar answered Sep 19 '22 18:09

2 revs