-
Bug
-
Resolution: Fixed
-
P2
-
1.0.2
-
1.1
-
sparc
-
solaris_2.4
-
Not verified
[This reports a bug we've known about for a while and have a tentative fix for]
Finalization occurs both asynchronously, as a result of a low-priority finalizer
thread running, or synchronously, as a result of an explicit or implicit call to
runFinalization(). Because of a hack done a long time ago, runFinalization()
backs off and returns trivially if it tries to run but finds someone in the middle
of finalizing something. For a system that becomes effectively CPU-bound,
like a server, the asynchronous finalizer thread can be interrupted in the middle
of finalizing something and never get to run again. Unfinalized objects will
pile up until GC proves ineffective and the system attempts to synchronously
finalize. At that point, because the async finalizer thread is in the middle of
finalizing, runFinalization() backs off and nothing gets done. Thus those
objects remain finalized and their space cannot be reclaimed. Instead, the
system must expand to satisfy the current memory request. The finalization
mechanism will only unwedge if the async finalizer thread somehow gets a
chance to run.
There is an obvious symptom of this when running with -verbosegc. The system
will GC many times getting less and less memory back per GC. When it eventually
runs out it will try to synchronously run finalizers. Before doing so it prints the
number of finalizers that it expects to run. As this happens repeatedly, the number
of finalizers to be run (but not being run) will continue to grow.
I've got code to fix this: rather than bailing out, someone wanting the finalization
mechanism just has to wait until it unsticks, and someone clearing out of
finalization has to signal waiters. This appears to fix the problem when running
Jeeves.
Finalization occurs both asynchronously, as a result of a low-priority finalizer
thread running, or synchronously, as a result of an explicit or implicit call to
runFinalization(). Because of a hack done a long time ago, runFinalization()
backs off and returns trivially if it tries to run but finds someone in the middle
of finalizing something. For a system that becomes effectively CPU-bound,
like a server, the asynchronous finalizer thread can be interrupted in the middle
of finalizing something and never get to run again. Unfinalized objects will
pile up until GC proves ineffective and the system attempts to synchronously
finalize. At that point, because the async finalizer thread is in the middle of
finalizing, runFinalization() backs off and nothing gets done. Thus those
objects remain finalized and their space cannot be reclaimed. Instead, the
system must expand to satisfy the current memory request. The finalization
mechanism will only unwedge if the async finalizer thread somehow gets a
chance to run.
There is an obvious symptom of this when running with -verbosegc. The system
will GC many times getting less and less memory back per GC. When it eventually
runs out it will try to synchronously run finalizers. Before doing so it prints the
number of finalizers that it expects to run. As this happens repeatedly, the number
of finalizers to be run (but not being run) will continue to grow.
I've got code to fix this: rather than bailing out, someone wanting the finalization
mechanism just has to wait until it unsticks, and someone clearing out of
finalization has to signal waiters. This appears to fix the problem when running
Jeeves.