How to properly implement a finalizer for detecting resource leaks in Java
Asked Answered
D

2

7

Let's say I have created some resource class with a close() method for cleaning up the resource, and I want to override finalize() to free the resource (and print a warning) if someone has forgotten to call close(). How can this be done properly?

  • Is it recommended only for native (JNI-allocated) resources?
  • What happens if you use a reference to another object that has been finalized, from a finalizer? If there are cyclic dependencies I don't see how the garbage collector can prevent you from accessing objects whose finalizers could have been executed.
  • Are there any better alternatives to overriding finalize() for detecting and/or dealing with resource leaks?
  • Any other pitfalls to be aware of when implementing a finalizer?

Note: I know that using finalize() is usually bad idea, and that it's not guaranteed to be called, there are several other questions discussing this. This question is specifically about how to implement a finalizer in Java, not about why you should (or shouldn't).

Daffodil answered 17/9, 2012 at 14:59 Comment(2)
I hope my answers helps. Let me know if I missed anything.Ashmore
Rephrased the second point about accessing possibly finalized objects from a finalizer. Still curious about what would be the implications of that.Daffodil
A
6

In effective java (2nd edition), Joshua goes in detail in Item #7 about how you can do this. He first suggests that you should almost never use finalizers. However, one reason to use it to only print a log statement saying you have a resource leak. He says one of the draw backs to doing it this way is that someone can extend your class and not properly call the super finalizer. So he suggests to do something like this in the subclass:

// Manual finalizer chaining
   @Override protected void finalize() throws Throwable {
       try {
           ... // Finalize subclass state
       } finally {
           super.finalize();
   } 
}

This is to ensure that if something breaks in the current class the finally will still get called. This maybe a bad solution because it depends on the person who is subclassing your class. An alternate solution is to use a guardian object file to get this done. This looks like:

// Finalizer Guardian idiom
   public class Foo {
// Sole purpose of this object is to finalize outer Foo object
      private final Object finalizerGuardian = new Object() {
         @Override protected void finalize() throws Throwable {
            ... // Finalize outer Foo object
         }
      };
      ...  // Remainder omitted
}

This is a cleaner approach because you know that no one can override that functionality.

The suggested way to closing resources is still implementing Closeable and make sure it is up to the user to close. As Josuha suggests, you shouldn't do any time sensitive operations in the finalize method. The JVM may choose to run it as sometime in the future. If you are depending on this method to do commits or something important then that is a bad idea.

Ashmore answered 17/9, 2012 at 15:23 Comment(0)
S
1

Is it recommended only for native (JNI-allocated) resources?

No. Your use case is also a valid one for finalizers. I mean logging resource leakage.

What happens if you access another Java object that has been finalized, in the finalizer?

If you can still access it, it is not finalized. Or maybe I'm missing something in your question.

I understand now. It might be the case that both A and B are eligible for garbage collection and there is a reference between them. It should be no problem as by default finalize() does nothing. If you write for both your objects custom finalize() methods you should write your code independent of the order they are finalized. You should also guard for the reference becoming null as the corresponding object might have been already garbage collected.

Are there any better alternatives to overriding finalize() for detecting and/or dealing with resource leaks?

I think the most important thing when using finalizers is detecting and logging/warning about the leakage not dealing with it. And the best moment to log this leakage is before the resource object is garbage collected. So finalizers are a natural fit for this.

I want to stress this: I wouldn't use finalizers to deal with a programmer that forgot to close the resource, but to inform him that he need to fix his code.

Any other pitfalls to be aware of when implementing a finalizer?

It seems there is also a performance penalty with objects that have finalizers. You should make a test see how it goes for you. If there is an important performance penalty I would try to imagine a mechanism to use finalizers only at development time to log resource leakage.

And take care when inheriting an object with finalizers as suggested by Amir Raminfar.

One more thing: take a look at the source code of [FileInputStream][1] or [FileOutputStream][2] they use finalizers for the same reason.

Stepheniestephens answered 17/9, 2012 at 15:51 Comment(4)
"If you can still access it, it is not finalized. Or maybe I'm missing something in your question." But if object A has a reference to object B, and B is finalized before A, then couldn't A access B from its finalizer?Daffodil
Edited my post and rephrased that question.Daffodil
So fields referring to objects that have been garbage collected will be null when the finalizer is called? Even final fields?Daffodil
Yes, even final fields. final specify that the reference once initialized never change.Stepheniestephens

© 2022 - 2024 — McMap. All rights reserved.