A recent failure of the AWT Reliability test appeared to be
caused by allocation outpacing the Garbage Collector.
Peter Kessler expressed the opinion that it was likely to be
the Finalizer that was being overwhelmed (see below for
his email on the subject). He also explained why finalization
is such a drain on resources, inhibits scalability, etc., and
expressed the opinion that finalizers could often be replaced
by more efficient methods:
> There are lots of good ideas floating around about how to get
> the "clean up" aspects of finalization without its drawbacks.
> Mostly they involve moving to weak or phantom references, or
> reducing what's accessible from any remaining final references.
> Maybe we should make up a "best practices" document based on
> examples we fix from the AWT/Swing code.
> ... peter
We should investigate the possibility of removing or decreasing
our dependence on finalizers in the Tiger time frame, or earlier.
Toward that end, I have filed bugs against AWT, Drag&Drop, 2D,
Swing, and Input Methods as placeholders.
--------- Begin email from Peter Kessler -------------------------
Remember, every object with a finalize method has to be discovered
to be otherwise unreachable once to put it on the finalizer queue,
then its finalize() method has to be run, then it has to be
discovered to be unreachable again before the storage for it
can be reused.
If your application uses 100% of the CPU cycles available,
the finalizer thread may fall behind. If the finalizer thread
falls behind, objects remain in the heap for too long, and the
heap expands to accomodate them (up to your maximum heap size),
but full collections slow down because the heap is bigger and
the collector has to look at more objects. (See my JavaOne
demo for details.)
If the problem goes away when you add small amounts of idle time
to your application, then the finalizer queue is probably the
problem, as the "idle" time is used to run the finalizer thread.
(We need better debugging hooks to let users see the length (and
volume) of the finalizer queue. The finalizer queue is in the
libraries, not the VM. From the VM I could find the finalizer
queue and run down it to find its length, but that's always seemed
like the wrong hammer to use. Adding a counter to Finalizer.java
seems like a better one.) For internal use, the Serviceability
Agent may be your friend.
> My question is: is this a bug? If so, what should be
> done about it?
The JLS doesn't promise that finalize() methods will be run
promptly. It does promise that they will be run before the
storage is reused. On the other hand, if the storage can't
be reused because the finalize() methods haven't been run,
then the collector can't reuse the space and you will run out
out of memory. People have suggested that when we run out of
memory we run the finalize() methods in preference to other
code, but if the finalize() methods need more memory they
won't run if we are out of memory.
It's also easy to back up the finalizer queue by having finalize()
methods that do a lot of work. If finalize() is more expensive
than allocation then a program that "just" does allocation
will back up the finalizer queue. Since allocation is parallelized
but finalization isn't (or need not be), running on a multi-processor
requires that you rethink the relative cost of allocation versus
--------- End email from Peter Kessler -------------------------
- Eric (###@###.###)