Fate of {System|Runtime}.runFinalization (Re: Ad removing finalize eventually

Kim Barrett kim.barrett at oracle.com
Thu Aug 5 00:45:51 UTC 2021

> On Aug 3, 2021, at 12:09 PM, Hans Boehm <hboehm at google.com> wrote:
> On Mon, Aug 2, 2021 at 11:32 PM Alan Bateman <Alan.Bateman at oracle.com>
> wrote:
> ...
>> When using cleaners or references then the typical response to resource
>> exhaustion will be System.gc with back-off/retry in a loop until the
>> resource can be allocated. Privileged ops in the JDK can do a bit better
>> by polling the pending reference list to see if there is still work to
>> do. So all a bit primitive.
> I agree that this is a bit primitive. Perhaps more importantly,
> it seems like a regression from finalization, where
> I can be reasonably sure that System.gc(); System.runFinalization();
> (with no locks held) will finalize all objects that can be finalized.
> (This ignores the case in which finalizers generate more Java garbage,
> but in most cases that's not a very significant effect.)

That privileged operation is Reference.waitForReferenceProcessing.  (If
there are references that haven't been enqueued, wait for some progress on
enqueuing and return true, else return false.)

I don't think there's a good reason for it being privileged or private. I
added it as part of JDK-8156500. I made it private and accessible as a
privileged operation because at the time only java.nio.Bits needed it, and
was previously using a privileged access to
Reference.tryHandlePendingReference (which was rightly privileged, and
removed by that change). So I had a model to follow (on occasion I pretend
to be a Java programmer), and I was too lazy to go through the process of
making waitForReferenceProcessing or some similar functionality public.

Later I noticed that function might be useful for runFinalization, and maybe
other things as well, such as being discussed here. See, for example,
JDK-6306116. Of course, if runFinalization were the only use-case, the wait
function still wouldn't need to be made public.

And there's a different problem, which is that System.gc may be disabled
entirely via -XX:+DisableExplicitGC.

> But I'm also not at all sure this is worth addressing now. If we want to
> move away
> from finalizers, I think it is important to make things easier in the new
> world
> with Cleaners. Currently there seem to be at least two things that make it
> significantly
> harder:
> 1) The lack of a default user-visible Cleaner seems to effectively tie up
> an additional
> thread per Cleaner-using-library. AFAICT, the decreased interference
> between Cleaners makes
> that desirable in some contexts, but the additional threads make it
> untenable in others.
> 2) The lack of a clean runFinalization alternative. I think this is
> actually an opportunity
> to improve things and motivate people to switch away from finalization. But
> currently
> it pushes in the wrong direction.

It was intentional that there's no "default" Cleaner. That would have all
the same problems as finalization wrto a cleanup that stalls and blocks
everything behind it.

As for the additional threads, an application is free to provide a widely
known Cleaner, and libraries that use the Cleaner API could provide a
mechanism for being told which Cleaner to use.

runFinalization provides a workaround for the stalled cleanup situation;
something similar could be added to Cleaner. But PhantomReference-based
cleanups are, I think, less prone to such problems because they aren't using
operations on the original object but are instead dealing just the the
dedicated PRef object.

Exposing waitForReferenceProcessing or something similar might help.

More information about the jdk-dev mailing list