Ad removing finalize eventually (Re: JEP 411 Headaches: Instrumenting private methods in the JDK for authorization checkpoints.

Kim Barrett kim.barrett at
Thu Aug 5 00:30:29 UTC 2021

> On Aug 3, 2021, at 9:08 AM, Rony G. Flatscher <Rony.Flatscher at> wrote:
> From first, simple tests on Java 8 it seems however, that System.runFinalization() will invoke
> finalize() on those Java objects that have no references at the time runFinalization() runs. So it
> does not follow the general gc strategy you describe. Running System.gc() does not have that effect,
> i.e. running finalize() of the very same Java objects without references at gc() time. So currently
> PhantomReferences to these Java objects that have no references would not be put on the queue but at
> some undefined later time, possibly never as you describe.
> The question then would be whether it was possible to have runFinalization() also look out for
> PhantomReference'd Java objects without references and put them on the queue at that point in time.
> This of course assumes that runFinalization() not only is able to identify unreferenced Java objects
> with a finalize method, but also unreferenced Java objects for which a PhantomReference got created
> for. [If so, runFinalization() may remain helpful even after finalize() got eventually removed.]

runFinalization spawns a thread that loops on getting the next enqueued
finalization and running it, exiting when there aren't any more in the
queue. There's a known race condition in this - see JDK-6306116. The GC adds
j.l.r.References and objects for finalization to the pending list, and the
in-Java reference processing thread takes those and adds them to their
associated queues. In the sequence "System.gc(); runFinalization();", the
new finalization thread can start, check the finalization queue and find it
still empty, and immediately exit because the reference processing thread
hasn't gotten around to transferring anything to that queue from the pending

runFinalization doesn't recognize unreferenced objects at all.  It just
deals with what the GC and the reference processing thread conspire to give
it (in cooperation with the default finalization processing thread).  That's
been true "forever" (JDK-6306116 was filed against JDK 6).

That is, runFinalization just adds a temporary thread to run in parallel
with the existing built-in finalization processing thread. And the way this
all works is no different from how the specified j.l.r.References are added
to their respective queues.

So I think there's something wrong with that test or the interpretation of
its behavior.

More information about the jdk-dev mailing list