Using runFinalizersOnExit

If an object cannot be accessed anymore, it is ready for garbage collection. Before the memory is labeled free, the VM will call the object’s method finalize in which you can clean up resources. However, it is possible that the GC may never run (for example, there’s always enough memory). As a design guideline, you should not free up any memory or release database connections inside your finalize method, as you don’t have any control over when it will be invoked. Instead, use a custom cleanup method that is explicitely called when the object is no longer needed.

runFinalizersOnExit specifies that finalize methods will be invoked when the application exits.

Eg. run this example, uncomment and run it again:

public class Main {
   public static final void main(String[] args) {
      //System.runFinalizersOnExit(true); 
      new Main();
   }
 
   protected void finalize() {
      System.out.println("Main object finalized");
   }
}

Since JDK1.2, runFinalizersOnExit has been deprecated. From the API: “This method is inherently unsafe. It may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, resulting in erratic behavior or deadlock.” Check out http://java.sun.com/products/jdk/1.2/docs/guide/misc/threadPrimitiveDeprecation.html for more information on Sun’s view on this issue.

For more information, I wrote to Hans Boehm, an expert on Runtime issues. Here’s what he’s got to say:


Disclaimer: I generally don’t agree with the Java designers on the details of the finalization mechanism. Thus you shouldn’t take this to be authoritative.

My impression is that there are actually two issues. Sun’s documentation implies that they were worried about synchronization issues. What happens if a thread is stuck holding the lock on A, a finalizer needs the lock on A, and if you’ve requested that finalizers be run on exit. You can’t exit?

I have a more fundamental problem with it. It makes it impossible to rely on any finalizer ordering, which I claim makes it impossible ti write reliable nontrivial finalizers. Let’s say that A’s finalizer needs access to object B, which is also finalizable. To make this concrete, let’s say that B actually holds a handle to some object C manipulated by JNI native code, and B’s finalizer explicitly deallocates C with a JNI call. Thus if A accesses B after it is finalized, B will try to follow the dangling native pointer to C. This arises for example if A somehow buffers requests to B, and has to flush them when it’s finalized.

This is somewhat inconvenient with Java finalizers, but it’s not too bad. A needs to ensure that a pointer to B is kept in some static location, so that B doesn’t get finalized first. When A’s finalizer is run, it clears the static pointer to B, readying B for finalization.

But this break with runFinalizersOnExit! At exit, finalizers to statically accessible objects have to be run. A and B may both be accessible, and the runtime has no way to tell which finalizer should be run first. Thus there is no way to prevent the dangling native pointer dereference.

In general with runFinalizersOnExit, you can’t assume that when a finalizer is run, method calls on other objects (or static method calls) are safe, since any other object may have previously been finalized. Presumably parts of the runtime/standard library may also already be finalized. Thus it’s not clear to me that you can really safely do anything useful in a finalizer. Certainly runFinalizersOnExit will break code not designed to run with it.

Hans