Sponsored Link •
The basic guideline
Although I suggested several guidelines for using finalizers in my Design Techniques article, my primary guideline was:
Don't design your Java programs such that correctness depends upon "timely" finalization.
I first heard this warning against writing Java programs that depend on "timely" finalization from Tim Lindolm, who was responsible for thread and garbage-collection mechanisms of Sun's original Java virtual machine (JVM). Tim gave this warning at the JVM Birds-of-a-Feather session at the first JavaOne conference in 1996. The problem with depending on timely finalization for program correctness is that you generally don't know how garbage collection will be performed inside a JVM. Therefore, since you don't know when (or even if) any particular object will be garbage collected, you don't know when or if it will be finalized.
The upshot of garbage collection in JVMs is that you must avoid writing Java programs that will break if certain objects aren't finalized by specific times during the program's execution. If you write such a program, it may work on some JVM implementations but fail on others.
Timely finalization and nonmemory resources
A more exact way to express the same basic guideline against timely finalization is to couch it in terms of finite nonmemory resources, such as sockets or file handles.
Don't depend on finalizers to release finite nonmemory resources.
This guideline considers that the primary way in which a program could depend on timely finalization is if the finalizer is used to release or retire some finite nonmemory resource, such as a file handle, a socket, memory allocated in a native method, or a running thread. Here's the example I gave in my Design Techniques article:
An example of an object that breaks this rule [against depending on timely finalization] is one that opens a file in its constructor and closes the file in its
finalize()method. Although this design seems neat, tidy, and symmetrical, it potentially creates an insidious bug. A Java program generally will have only a finite number of file handles at its disposal. When all those handles are in use, the program won't be able to open any more files.
A Java program that makes use of such an object (one that opens a file in its constructor and closes it in its finalizer) may work fine on some JVM implementations. On such implementations, finalization would occur often enough to keep a sufficient number of file handles available at all times. But the same program may fail on a different JVM whose garbage collector doesn't finalize often enough to keep the program from running out of file handles. Or, what's even more insidious, the program may work on all JVM implementations now but fail in a mission-critical situation a few years (and release cycles) down the road.