WEBINAR:
On-Demand
Building the Right Environment to Support AI, Machine Learning and Deep Learning

inalization is a feature of the Java programming language that allows you to perform postmortem cleanup on objects that the garbage collector has found to be unreachable. It is typically used to reclaim native resources associated with an object. The following is a simple finalization example:
public class Image1 {
// pointer to the native image data
private int nativeImg;
private Point pos;
private Dimension dim;
// it disposes of the native image;
// successive calls to it will be ignored
private native void disposeNative();
public void dispose() { disposeNative(); }
protected void finalize() { dispose(); }
static private Image1 randomImg;
}
Some time after an Image1
instance has become unreachable, the Java virtual machine (JVM) will call its finalize()
method to ensure that the native resource that holds the image data (pointed to by the integer nativeImg
in the example) has been reclaimed. Notice, however, that the finalize()
method, despite its special treatment by the JVM, is an arbitrary method that contains arbitrary code. In particular, it can access any field in the object (pos
and dim
in the example). Surprisingly, it can also make the object reachable again by, say, making it reachable from a static field (e.g., randomImg = this;
). I really don't recommend the latter programming practice, but unfortunately the Java programming language allows it.
The following steps describe the lifetime of a finalizable object obj
that is, an object whose class has a non-trivial finalizer (see Figure 1):
 | |
Figure 2. Garbage Collector Determines That obj Is Unreachable |
- When
obj
is allocated, the JVM internally records that obj
is finalizable (this typically slows down the otherwise fast allocation path that modern JVMs have).
- When the garbage collector determines that
obj
is unreachable, it notices that obj
is finalizable (as it had been recorded upon allocation) and adds it to the JVM's finalization queue. It also ensures that all objects reachable from obj
are retained, even if they are otherwise unreachable, as they might be accessed by the finalizer. Figure 2 illustrates this for an instance of Image1
.
- At some point later, the JVM's finalizer thread will dequeue
obj
, call its finalize()
method, and record that obj
's finalizer has been called. At this point, obj
is considered to be finalized.
- When the garbage collector rediscovers that
obj
is unreachable, it will reclaim its space along with everything reachable from it (provided that the latter is otherwise unreachable).
Notice that the garbage collector needs a minimum of two cycles (maybe more) to reclaim obj
and needs to retain all other objects reachable from obj
during this process. If a programmer is not careful, this can create temporary, subtle, and unpredictable resource-retention issues. Additionally, the JVM does not guarantee that it will call the finalizers of all the finalizable objects that have been allocated; it might exit before the garbage collector discovers some of them to be unreachable.