How to replace Object.finalize()

There are many articles and blog posts about this topic but rarely are they complete. I’ll cover finalizers, Finalizer Guardian idiom, Dispose Pattern, PhantomReference and Cleanable.

Avoid finalizers!

So far the article by Joshua Bloch is the best I could find:
Creating and Destroying Java Objects – Item 7: Avoid finalizers

He also gives us an alternative: The Finalizer Guardian idiom.

Microsoft has adopted the finalizers for their .NET framework. With all the same problems.
They then suggested this pattern: Dispose Pattern
It consists of 12 DOs and CONSIDERs. But there are also seven AVOIDs and DO NOTs.
They also have another article about implementation of this pattern:
Implementing a Dispose Method
But that’s just lines and lines of boiler plate code. And it just introduces new problems and pitfalls.

Problems with Finalizers

I’ll list some of the problems here:

  • super.finalize() often forgotten.
  • Only one finalize method available per class.
  • Runs in a random thread.
    • risk of deadlocks
    • visibility problems (memory model)
  • All exceptions are lost.
  • GC can’t reclaim memory until finalizers are run.
    • Risk of OutOfMemoryException during finalization.
  • How to clean up singletons and other objects that exist till the end of the JVM?
  • runFinalizersOnExit is flawed and deprecated.
  • finalize will not run for all objects.
  • finalize will not run promptly.

Some blogs claim that there is no guarantee that a finalizer will ever run. Joshua Bloch states correctly that there is no guarantee they’ll be executed promptly [JLS, 12.6]. But they are not executed if the object still exists when the JVM is shutting down. And when you design a class you often can’t make sure the call site or extending classes will not break the finalizers.

Examples

not final

Often a method or class can’t be final. But how  will you make sure extending classes will run your finalize method?

/** Class and method not final. */
static class Foo {
  @Override
  protected void finalize() throws Throwable {
    // not final -> extending class doesn't have to call this method.
  }
}

OutOfMemoryError

Why would you want to run code when the memory is already full? That’s when GC usually runs.

static final class Foo {
  @Override
  protected void finalize() throws Throwable, OutOfMemoryError {
    // What if memory is already running out?
    // Then even a small array could fail:
    byte[] bytes = new byte[Integer.MAX_VALUE];
    // OutOfMemoryError was thrown!
    System.out.println("This won't run");
    // Also not invoked:
    super.finalize();
  }
}

Immortal Objects

Some objects (singletons, enum constants, static members) will never be discarded by the GC.

static final class SingleFoo {
  public static final SingleFoo INSTANCE = new SingleFoo();
  @Override
  protected void finalize() throws Throwable {
    // This will never run!
  }
}

Phantoms of the mortal Objects

What Joshua Bloch and most other blogs do not mention is the other alternative:
PhantomReference

I couldn’t find any code that actually uses this and works. Just some theoretical demo code that often didn’t even do what was promised. There’s an entry in the JProfiler help that gives you an idea but it’s hard to actually apply it to a project.

That’s why I created an abstraction of it. Then I’ve found out that this already exists: sun.misc.Cleaner
With the release of Java 9 this API was renamed to java.util.ref.Cleaner. You can then implement an interface called Cleanable, which makes it easy to clean up after some object.

If you are interested in more information about PhantonReferences I suggest you study the code of my project and it’s documentation (or Cleaner from JDK 9). The project is rather small and contains a class Example that shows how to use it.

3 thoughts on “How to replace Object.finalize()”

Leave a Reply

Your email address will not be published. Required fields are marked *