Sponsored Link •
So what are finalizers good for?
By now you may be getting the feeling that you don't have much use for finalizers. While it is likely that most of the classes you design won't include a finalizer, there are some reasons to use finalizers.
One reasonable, though rare, application for a finalizer is to free
memory allocated by native methods. If an object invokes a native
method that allocates memory (perhaps a C function that calls
malloc()), that object's finalizer could invoke a native
method that frees that memory (calls
free()). In this
situation, you would be using the finalizer to free up memory allocated
on behalf of an object -- memory that will not be automatically
reclaimed by the garbage collector.
Another, more common, use of finalizers is to provide a fallback
mechanism for releasing non-memory finite resources such as file
handles or sockets. As mentioned previously, you shouldn't rely on
finalizers for releasing finite non-memory resources. Instead, you
should provide a method that will release the resource. But you may
also wish to include a finalizer that checks to make sure the resource
has already been released, and if it hasn't, that goes ahead and
releases it. Such a finalizer guards against (and hopefully will not
encourage) sloppy use of your class. If a client programmer forgets to
invoke the method you provided to release the resource, the
finalizer will release the resource if the object is ever garbage
finalize() method of the
LogFileManager class, shown later in this article, is an
example of this kind of finalizer.
Avoid finalizer abuse
The existence of finalization produces some interesting complications for JVMs and some interesting possibilities for Java programmers. For a discussion of the impact of finalizers on JVMs, see the sidebar, a short excerpt from chapter 9, "Garbage Collection," of my book, Inside the Java Virtual Machine.
What finalization grants to programmers is power over the life and death of objects. In short, it is possible and completely legal in Java to resurrect objects in finalizers -- to bring them back to life by making them referenced again. (One way a finalizer could accomplish this is by adding a reference to the object being finalized to a static linked list that is still "live.") Although such power may be tempting to exercise because it makes you feel important, the rule of thumb is to resist the temptation to use this power. In general, resurrecting objects in finalizers constitutes finalizer abuse.
The main justification for this rule is that any program that uses resurrection can be redesigned into an easier-to-understand program that doesn't use resurrection. A formal proof of this theorem is left as an exercise to the reader (I've always wanted to say that), but in an informal spirit, consider that object resurrection will be as random and unpredictable as object finalization. As such, a design that uses resurrection will be difficult to figure out by the next maintenance programmer who happens along -- who may not fully understand the idiosyncrasies of garbage collection in Java.
If you feel you simply must bring an object back to life, consider
cloning a new copy of the object instead of resurrecting the same old
object. The reasoning behind this piece of advice is that garbage
collectors in the JVM invoke the
finalize() method of an
object only once. If that object is resurrected and becomes
available for garbage collection a second time, the object's
finalize() method will not be invoked again.