Now that we've seen how to create objects, it's time to talk about their destruction. If you're accustomed to programming in C or C++, you've probably spent time hunting down memory leaks in your code. Java takes care of object destruction for you; you don't have to worry about memory leaks, and you can concentrate on more important programming tasks.
Java uses a technique known as garbage collection to remove objects that are no longer needed. The garbage collector is Java's grim reaper. It lingers, usually in a low priority thread, stalking objects and awaiting their demise. It finds them, watches them, and periodically counts references to them to see when their time has come. When all references to an object are gone, and it's no longer accessible, the garbage-collection mechanism reclaims it and returns the space to the available pool of resources.
There are many different algorithms for garbage collection; the Java virtual machine architecture doesn't specify a particular scheme. It's worth noting, though, that current implementations of Java use a conservative mark and sweep system. Under this scheme, Java first walks through the tree of all accessible object references and marks them as alive. Then Java scans the heap looking for identifiable objects that aren't so marked. Java finds objects on the heap because they are stored in a characteristic way and have a particular signature of bits in their handles unlikely to be reproduced naturally. This kind of algorithm doesn't suffer from the problem of cyclic references, where detached objects can mutually reference each other and appear alive.
By default, the Java virtual machine is configured to run the garbage
collector in a low-priority thread, so that the garbage collector runs
periodically to collect stray objects. With the
java interpreter that comes with the
JDK, you can turn off garbage collection by using
the -noasyncgc command-line option. If you do this,
the garbage collector will be run only if it's requested explicitly or
if the Java virtual machine runs out of memory.
A Java application can prompt the garbage collector to make a sweep explicitly
by invoking the System.gc() method. An extremely
time-sensitive Java application might use this to its advantage by running
in an interpreter with asynchronous garbage collection deactivated and
scheduling its own cleanup periods. This issue is necessarily implementation
dependent, however, because on different platforms, garbage collection may
be implemented in different ways. On some systems it may be continuously
running in hardware.
Before an object is removed by garbage collection, its
finalize() method is invoked to give it a last
opportunity to clean up its act and free other kinds of resources
it may be holding. While the garbage collector can reclaim memory
resources, it may not take care of things like closing files and
terminating network connections gracefully or efficiently. That's what
the finalize() method is for.
An object's finalize() method is called once and only once before the object is garbage collected.
However, there's no guarantee when that will happen.
Garbage collection may never run on a system that is not short of memory.
It is also interesting to note that finalization and collection occur in
two distinct phases of the garbage-collection process. First items are
finalized; then they are collected. It is therefore possible that
finalization could (intentionally or unintentionally) create a
lingering reference to the object in question, postponing its garbage
collection. The object could, of course, be subject to collection later,
if the reference goes away, but its finalize() method would not be
called again.
The finalize() methods of superclasses
are not invoked automatically for you. If you need to chain together
the finalization of your parent classes, you should invoke the
finalize() method of your superclass, using super.finalize().
We discuss inheritance and overridden methods in Chapter 6.