History of finalizer execution and gc progress?
Peter B. Kessler
Peter.B.Kessler at Oracle.COM
Wed Jun 18 22:35:47 UTC 2014
As far back as I can remember (I never worked on the implementation of the "classic" JVM), the JVM discovers objects that should have their finalize() method called and puts them on a queue to be handled by Java library code. That means the JVM can continue collecting garbage even if that queue isn't being drained. Also as far back as I can remember, the Java library code calls the finalize() method from a thread dedicated to that. Cf. the static block at the end of  and , to cite only openly-available sources.
As to "still in use around 2005", it would help to have a JDK version number.
One of the things I used to do to dissuade people from using finalize() methods was to create and drop an object with a finalize() method that blocked, because that *would* block any subsequent calls from the Java library code to finalize() methods. Some people worked around that (or in real life :-) by calling Runtime.runFinalization() (usually by calling System.runFinalization()), which spins up an additional thread to drain the queue of discovered objects with non-trivial finalize() methods. Runtime.runFinalization() has been around since the beginning, though of course the specification is a little vague.
You might be able to disable the collection of unreachable objects by misusing calls to the JNI functions GetPrimitiveArrayCritical and friends.
As long as you have all the infrastructure of your own thread, etc., I would recommend that you switch your uses of finalize() to WeakReferences (or PhantomReferences) and your own threads to drain your own queues. Then you would own all your code and wouldn't have to worry about interactions with other object types.
On 06/17/14 00:15, Stephan Bergmann wrote:
> Hi all,
> Does anybody recollect historical details of how execution of (potentially long-running) finalizers impacted overall gc progress?
> From the behavior of a small test program run on OpenJDK 8, it looks like recent JVMs at least offload all finalizer calls to a single dedicated thread, so that a blocking finalizer blocks finalization (and thus reclamation) of other garbage objects with explicit finalizers, but reclamation of other garbage proceeds unhindered.
> But how was the behavior in the past? Was it so that in older JVMs (still in use around 2005) execution of a blocking finalizer could block reclamation of /all/ garbage, even of those objects that did not have explicit finalizers?
> (I'm asking because in LibreOffice we have a dedicated thread to which we offload the actual work done by certain objects' finalize methods, introduced around 2005 to work around memory starvation in case one of those finalizers took too long. But I can't remember whether that was because no garbage at all was reclaimed in such a scenario---and we could drop our additional thread again today---, or because it blocked finalization of unrelated objects with explicit finalizers---in which case we would need to keep our additional thread.)
More information about the hotspot-gc-dev