Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are there finalizers in java and c#?

I'm not quite understanding why there are finalizers in languages such as java and c#. AFAIK, they:

  • are not guaranteed to run (in java)
  • if they do run, they may run an arbitrary amount of time after the object in question becomes a candidate for finalization
  • and (at least in java), they incur an amazingly huge performance hit to even stick on a class.

So why were they added at all? I asked a friend, and he mumbled something about "you want to have every possible chance to clean up things like DB connections", but this strikes me as a bad practice. Why should you rely on something with the above described properties for anything, even as a last line of defense? Especially when, if something similar was designed into any API, said API would get laughed out of existence.

like image 228
RCIX Avatar asked Dec 05 '09 01:12

RCIX


People also ask

Why there is no destructor in Java?

Java has its own garbage collection implementation so it does not require any destructor like C++ . This makes Java developer lazy in implementing memory management. Still we can have destructor along with garbage collector where developer can free resources and which can save garbage collector's work.

What is the purpose of finalization in Java?

finalize() method in Java is used to release all the resources used by the object before it is deleted/destroyed by the Garbage collector. finalize is not a reserved keyword, it's a method. Once the clean-up activity is done by the finalize() method, garbage collector immediately destroys the Java object.

Why do we need finalize?

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. If we are overriding the finalize() method then it's our responsibility to call the finalize() method explicitly.

What is the use of finalize in C++?

Finalize is similar to traditional C++ destructors, as each is responsible for freeing object resources. C++ destructors are executed immediately when an object goes out of scope, whereas finalize is called during object cleanup at GC. In C#, finalize cannot be directly called or overridden.


2 Answers

Well, they are incredibly useful, in certain situations.

In the .NET CLR, for example:

  • are not guaranteed to run

The finalizer will always, eventually, run, if the program isn't killed. It's just not deterministic as to when it will run.

  • if they do run, they may run an arbitrary amount of time after the object in question becomes a candidate for finalization

This is true, however, they still run.

In .NET, this is very, very useful. It's quite common in .NET to wrap native, non-.NET resources into a .NET class. By implementing a finalizer, you can guarantee that the native resources are cleaned up correctly. Without this, the user would be forced to call a method to perform the cleanup, which dramatically reduces the effectiveness of the garbage collector.

It's not always easy to know exactly when to release your (native) resources- by implementing a finalizer, you can guarantee that they will get cleaned up correctly, even if your class is used in a less-than-perfect manner.

  • and (at least in java), they incur an amazingly huge performance hit to even stick on a class

Again, the .NET CLR's GC has an advantage here. If you implement the proper interface (IDisposable), AND if the developer implements it correctly, you can prevent the expensive portion of finalization from occuring. The way this is done is that the user-defined method to do the cleanup can call GC.SuppressFinalize, which bypasses the finalizer.

This gives you the best of both worlds - you can implement a finalizer, and IDisposable. If your user disposes of your object correctly, the finalizer has no impact. If they don't, the finalizer (eventually) runs and cleans up your unmanaged resources, but you run into a (small) performance loss as it runs.

like image 140
Reed Copsey Avatar answered Sep 20 '22 12:09

Reed Copsey


Hmya, you are getting a picture painted here that's a bit too rosy. Finalizers are not guaranteed to run in .NET either. Typical mishaps are a finalizer that throws an exception or a time-out on the finalizer thread (2 seconds).

That was a problem when Microsoft decided to provide .NET hosting support in SQL Server. The kind of application where restarting the app to solve resource leaks isn't considered a viable workaround. .NET 2.0 acquired critical finalizers, enabled by deriving from the CriticalFinalizerObject class. The finalizer of such a class must adhere to the rulez of constrained execution regions (CERs), essentially a region of code where exceptions are suppressed. The kind of things you can do in a CER are very limited.

Back to your original question, finalizers are necessary to release operating system resources other than memory. The garbage collector manages memory very well but doesn't do anything to release pens, brushes, files, sockets, windows, pipes, etc. When an object uses such a resource, it must make sure to release the resource after it is done with it. Finalizers ensure that happens, even when the program forgot to do so. You almost never write a class with a finalizer yourself, operating resources are wrapped by classes in the framework.

The .NET framework also has a programming pattern to ensure such a resource is released early so the resource doesn't linger around until the finalizer runs. All classes that have finalizers also implement the IDisposable.Dispose() method, allowing your code to release a resource explicitly. This is often forgotten by a .NET programmer but that doesn't typically cause problems because the finalizer ensures it will eventually be done. Many .NET programmers have lost hours of sleep worrying whether or not all Dispose() calls are taken care of and massive numbers of threads have been started about it on forums. Java folks must be a happier lot.


Following up on your comment: exceptions and timeouts in the finalizer thread is something that you don't have to worry about. Firstly, if you find yourself writing a finalizer, take a deep breath and ask yourself if you're on the Right Path. Finalizers are for framework classes, you should be using such a class to use an operating resource, you'll get the finalizer built into that class for free. All the way down to the SafeHandle classes, they have a critical finalizer.

Secondly, finalizer thread failures are gross program failures. Similar to getting an OutOfMemory exception or tripping over the power cord and unplugging the machine. There isn't anything you can do about them, other than fixing the bug in your code or re-route the cable. It was important for Microsoft to design critical finalizers, they can't rely on all programmers that write .NET code for SQL Server to get that code right. If you fumble a finalizer yourself then there is no such liability, it will be you that gets the call from the customer, not Microsoft.

like image 21
Hans Passant Avatar answered Sep 24 '22 12:09

Hans Passant