Why does the .NET Object have a Finalize () method?

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

Object.Finalize is called only from the code of the auto-generated finalizer:

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

Thus, having an arbitrary class derived from Object will not call Object.Finalize - you need a finalizer for Object.Finalize to make sense, and for most classes it does not make sense and is not used (not to mention that the implementation is empty on actually).

It would be too difficult to verify the existence of the Finalize method in the class without redefining Object.Finalize and creating a root finalizer without try {} finally { base.Finalize () }? Something similar to the Add method to initialize the collection β€” you don’t need to implement any interface or redefine this method β€” just implement the public void Add(item) method.

This would complicate the C # compiler a bit, but it would start the finalizer a bit faster by removing one redundant call, and most importantly, make the Object class more understandable without protecting the Finalize method with an empty implementation, while it does not need to finalize anything.

It may also be possible to implement the FinalizableObject class derived from Object and make a compiler for all classes that have a finalizer. It can implement IDisposable and make the removal template recommended by Microsoft repeatedly, without the need for its implementation in each class. In fact, I am surprised that such a base class does not exist.

+5
source share
2 answers

Edit

Garbage collection does not call a child implementation of Object.Finalise unless the method is overridden. Why is it available for all objects? So that it can be redefined when necessary, but if it is not, it does not affect performance. Looking at the documentation here , she states:

The Object class does not provide an implementation of the Finalize method, and the garbage collector does not mark the types obtained from the object to complete unless they override the Finalize method.

Completion notes

A quote directly from Ben Watson is a great book Writing High Performance .NET Code, as it explains a lot better than I ever could;

Never run a finalizer unless it is required. Finalizers are code that the garbage collector runs to clean up unmanaged resources. They are called from one thread one by one, and only after the garbage collector declares the object dead after collection. This means that if your class implements a finalizer, you guarantee that it will remain in memory even after the collection that was supposed to kill it. This reduces the overall efficiency of the GC and ensures that your program allocates CPU resources to clean your object.

If you are running a finalizer, you must also implement an IDisposable interface to provide 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 clear the object properly, without having to run the finalizer. 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 believe that finalizers are guaranteed to work. This is usually true, but not entirely true. If the program is forcibly terminated, the code no longer runs, and the process immediately dies. There is also a time limit on how long all finalizers will be issued at the end of the process. If your finalizer is at the end of the list, it may be skipped. Moreover, because finalizers are executed sequentially, if in another finalizer there is an infinite loop error in it, then there are no finalizers after they will ever be executed. Although finalizers do not start in the GC thread, they are started by GC, so if you do not have collections, finalizers will not start. Therefore, you should not rely on finalizers to clean up a state external to your process.

Microsoft has a good record on finalizers and a one-time template here

+9
source

The C # language destructor syntax is too overshadowed by what the finalizer does. Perhaps it’s best to demonstrate an example 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:

Finalized finalizer called Basic Finalizer called

There are some noteworthy things about this behavior. The Example class itself does not have a finalizer, but its base class finalizers are invoked anyway. That the Derived class Finalizer is called before the Base class finalizer is not random. Note that the finalizer of the Derived class does not have a call to base.Finalize (), although the MSDN article for Object.Finalize () requires it to be executed, but it is still called.

You can easily recognize this behavior, this is the way the virtual method behaves. The one whose redefinition invokes the underlying method is usually overridden by virtual methods. Otherwise, exactly what is inside the CLR, Finalize () is a simple 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(); } } 

Invalid code, but a way to reverse it from MSIL. C # syntactic sugar ensures that you never forget to call the base finalizer and that it cannot be interrupted by interrupting a thread or unloading an AppDomain. The C # compiler does not help and automatically generates a finalizer for the Example class; The CLR does the necessary work of finding the finalizer of the derived class itself, crossing the method tables of the base classes until it finds them. It also helps in the class loader by setting a flag indicating that the example has base classes with a finalizer, so it should be handled specifically by the GC. The base class finalizer calls Object.Finalize (), although it does nothing.

So, the key point is that Finalize () is actually a virtual method. Therefore, this object requires a slot in the method table, so a derived class can override it. Whether it was done otherwise is rather subjective. Of course, it is not easy and not without coercion to each implementation of the language in a special case.

+8
source

Source: https://habr.com/ru/post/1272534/


All Articles