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

此生再无相见时 提交于 2020-01-02 04:35:11

问题


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).


回答1:


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.




回答2:


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.



来源:https://stackoverflow.com/questions/12461995/how-to-properly-implement-a-finalizer-for-detecting-resource-leaks-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!