Question

Effective Java says :

There is a severe performance penalty for using finalizers.

Why is it slower to destroy an object using the finalizers?

Was it helpful?

Solution

Because of the way the garbage collector works. For performance, most Java GCs use a copying collector, where short-lived objects are allocated into an "eden" block of memory, and when the it's time for that generation of objects to be collected, the GC just needs to copy the objects that are still "alive" to a more permanent storage space, and then it can wipe (free) the entire "eden" memory block at once. This is efficient because most Java code will create many thousands of instances of objects (boxed primitives, temporary arrays, etc.) with lifetimes of only a few seconds.

When you have finalizers in the mix, though, the GC can't simply wipe an entire generation at once. Instead, it needs to figure out all the objects in that generation that need to be finalized, and queue them on a thread that actually executes the finalizers. In the meantime, the GC can't finish cleaning up the objects efficiently. So it either has to keep them alive longer than they should be, or it has to delay collecting other objects, or both. Plus you have the arbitrary wait time of actually executing the finalizers.

All these factors add up to a significant runtime penalty, which is why deterministic finalization (using a close() method or similar to explicitly finalize the object's state) is usually preferred.

OTHER TIPS

Having actually run into one such problem:

In the Sun HotSpot JVM, finalizers are processed on a thread that is given a fixed, low priority. In a high-load application, it's easy to create finalization-required objects faster than the low-priority finalization thread can process them. Meanwhile, the space on the heap used by the finalization-pending objects is unavailable for other uses. Eventually, your application may spend all of its time garbage collecting, because all of the available memory is in use by objects pending finalization.

This is, of course, in addition to the other many reasons to not use finalizers that are described in Effective Java.

I just picked up my copy Effective Java off my desk to see what he's referring to.

If you read Chapter 2, Section 6, he goes into good detail about the various performance hits.

You can't know when the finalizer will run, or even if it will at all. Because those resources may never be claimed, you will have to run with fewer resources.

I would recommend reading the entirety of the section - it explains things much better than I can parrot here.

My thought is this: Java is a garbage collected language, which deallocates memory based on its own internal algorithms. Every so often, the GC scans the heap, determines which objects are no longer referenced, and de-allocates the memory. A finalizer interrupts this and forces the deallocation of memory outside of the GC cycle, potentially causing inefficiencies. I think best practices are to use finalizers only when ABSOLUTELY necessary such as freeing file handles or closing DB connections which should be done deterministically.

If you read the documentation of finalize() closely, you will notice that finalizers enable an object to prevent being collected by the GC.

If no finalizer is present, the object simply can be removed and does not need any more attention. But if there is a finalizer, it needs to be checked afterwards, if the object didn't become "visible" again.

Without knowing exactly how the current Java garbage collection is implemented (actually, because there are different Java implementations out there, there are also different GCs), you can assume that the GC has to do some additional work if an object has a finalizer, because of this feature.

One reason I can think of is that explicit memory cleanup is unnecessary if your resources are all Java Objects, and not native code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top