Don’t rely on Java finalizers

Don’t rely on Java finalizers

Recently I was facing a problem where a Java application should persist a part of its state when it was closed. This was already implemented but seemed to work just unreliably and it was not clearly reproducible when it worked properly and when it failed. After analyzing the existing source code I figured out that finalizers were used to implement the functionality by delegating the call of the persist logic to the garbage collector. This seems like a very good idea at first but lacks in reliability. As a short note up front don’t use finalizers for important things.

A finalizer is a method which represents the opposite of a constructor. It is a method with the purpose to do some cleanup work, free up some memory and so on which gets called by the garbage collector before the object gets collected. A simple example would look like this
protected void finalize() {“start important work before GC”);

This simple example would try to get some data structure and persist it before the garbage collector deletes the object. The idea to delegate this call to the GC is generally good as the GC only collects the object when it is not needed anymore and my data structure will by no chance be modified anymore. As a result I didn’t need to come up with my own idea on how to detect when my application (or the part of the application) is closed and the state should get persisted. All this is absolutely right but the problem with this approach is that you need to realize that it is not guaranteed that the garbage collector will call the finalize method.
When a garbage collector is run depends on its configuration and the memory usage. Different GCs will have a whole different behavior but what always is in common is that they will only run on an object when there is no reference to it anymore. With that in mind you can easily think of a scenario where you forgot that you hold a reference of your object that should be finalized somewhere and as a result your persisting will never take place.
Furthermore as it is not guaranteed when the GC and according to that when the finalizer will run it is also possible that you close your application and the termination of the JVM will take place before the GC runs. In that case your persistence also will never be executed. This things are incredibly hard to catch and debug.
As an advice you should never use the finalizer, or at least not for anything important. As I have never seen any good use of a finalizer I consider it to be suspicious when I encounter it.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.