Replacing Finalizers With Phantom References

## Replacing Finalizers With Phantom References |

### 1. Why finalizers are bad

Sometimes one must perform pre-garbage collection actions such as freeing resources. In a JDBC driver, for example, a database connection may be held by a connection object. Before the connection object is garbage collected, the actual database connection must be closed. In such a case, one typically cannot rely on the `close()` method being called by the user application code.

Most often, finalizers are used to solve this problem. A finalizer is created by overriding the `finalize()` method of `java.lang.Object`. In that case, before the object is garbage collected, this finalize method will be called. Unfortunately, there are severe problems with the design of this finalizer mechanism. Using finalizers has a negative impact on the performance of the garbage collector and can break data integrity of your application if you're not very careful since the "finalizer" is invoked in a random thread, at a random time. If you use a lot of finalizers, the finalizer system may be completely overwhelmed which can lead to `OutOfMemoryError`s. In addition, you have no control about when a finalizer will be run, so it can create problems with locking, the shutdown of the JVM and other exceptional circumstances.

The solution is to eliminate finalizers where they are not strictly required and replace the necessary ones with phantom references.

### 2. What are phantom references?

Phantom references can be used to perform actions before an object is garbage collected in a safe way. In the constructor of a `java.lang.ref.PhantomReference`, you specify a `java.lang.ref.ReferenceQueue` where the phantom reference will be enqueued once the referenced object becomes "phantom reachable". Phantom reachable means unreachable other than through the phantom reference. The initially confusing thing is that although the phantom reference continues to hold the referenced object in a private field (unlike soft or weak references), its `getReference()` method always returns `null`. This is so that you cannot make the object strongly reachable again.

From time to time, you can poll the reference queue and check if there are any new phantom references whose referenced objects have become phantom reachable. In order to be able to to anything useful, one can for example derive a class from `java.lang.ref.PhantomReference` that references resources that should be freed before garbage collection. The referenced object is only garbage collected once the phantom reference becomes unreachable itself.

### 3. How to replace finalizers with phantom references

Let's continue with the example of the JDBC driver above: Before a connection object is garbage collected, the actual database connection must be closed. The following steps are necessary to achieve this with phantom references:

- Add data structure that holds phantom references
  The JDBC driver class gets a data structure that holds phantom references to the connection objects. A private field

            private LinkedList phantomReferences = new LinkedList();

  would be appropriate. This is necessary to ensure that phantom references are not garbage collected as long as they have not been handled by the reference queue.
- Create reference queue
  Before a connection object will be garbage collected, its phantom reference will be enqueued into the associated reference queue. The JDBC driver thus gets an additional private field

            private ReferenceQueue queue = new ReferenceQueue();

- Derive a class from PhantomReference that references resources
  You will not be able to access the original object from a phantom reference. Therefore, you have to add the resources that must be freed to the phantom reference itself. In our example JDBC driver this could be a class named `DatabaseConnection`. The phantom reference class will thus look like:

            public class ConnectionPhantomReference extends PhantomReference {
                private DatabaseConnection databaseConnection;

                public MyPhantomReference(ConnectionImpl connection, ReferenceQueue queue) {
                    super(connection, queue);
                    databaseConnection = connection.getDatabaseConnection();
                }

                public void cleanup() {
                    databaseConnection.close();
                }
            }

  The custom phantom reference extracts the resource object from the implementation class of the connection and saves it in a private field. It additionally provides a `cleanup()` method that can be invoked once after the phantom reference is taken out of the reference queue.
- Create and remember phantom references when objects are created
  When a connection object is created, a corresponding `ConnectionPhantomReference` must be created as well and added to the `phantomReferences` list:

            phantomReferences.add(new ConnectionPhantomReference(connection, queue));

- Create reference queue handler thread
  When a phantom reference is added to the queue by the garbage collector, no further action is taken. You have to handle and empty the reference queue yourself. It's best to create a separate daemon thread that removes phantom references from the queue and invokes the cleanup method:

            Thread referenceThread = new Thread() {
                public void run() {
                    while (true) {
                        try {
                            ConnectionPhantomReference ref = (ConnectionPhantomReference)queue.remove();
                            ref.close();
                            phantomReferences.remove(ref);
                        } catch (Exception ex) {
                          // log exception, continue
                        }
                    }
                }
            };
            referenceThread.setDaemon(true);
            referenceThread.start();

  The phantom reference is removed from the `phantomReferences` list. Now the phantom reference is unreferenced itself and the referenced object can be garbage collected.