[9] RFR (M): 8079205: CallSite dependency tracking is broken after sun.misc.Cleaner became automatically cleared (original) (raw)

Peter Levart peter.levart at gmail.com
Sat May 9 09:33:43 UTC 2015


Hi Vladimir,

On 05/08/2015 07:16 PM, Vladimir Ivanov wrote:

http://cr.openjdk.java.net/~vlivanov/8079205/webrev.01 https://bugs.openjdk.java.net/browse/JDK-8079205

Your Finalizator touches are good. Supplier interface is not needed as there is a public Reference superclass that can be used for return type of JavaLangRefAccess.createFinalizator(). You can remove the import for Supplier in Reference now.

Recent change in sun.misc.Cleaner behavior broke CallSite context cleanup. CallSite references context class through a Cleaner to avoid its unnecessary retention. The problem is the following: to do a cleanup (invalidate all affected nmethods) VM needs a pointer to a context class. Until Cleaner is cleared (and it was a manual action, since Cleaner extends PhantomReference isn't automatically cleared according to the docs), VM can extract it from CallSite.context.referent field.

If PhantomReference.referent wasn't cleared by VM when PhantomReference was equeued, could it happen that the referent pointer was still != null and the referent object's heap memory was already reclaimed by GC? Is that what JDK-8071931 is about? (I cant't see the bug - it's internal). In that respect the Cleaner based solution was broken from the start, as you did dereference the referent after Cleaner was enqueued. You could get a != null pointer which was pointing to reclaimed heap. In Java this dereference is prevented by PhantomReference.get() always returning null (well, nothing prevents one to read the referent field with reflection though).

FinalReference(s) are different in that their referent is not reclaimed while it is still reachable through FinalReference, which means that finalizable objects must undergo at least two GC cycles, with processing in the reference handler and finalizer threads inbetween the cycles, to be reclaimed. PhantomReference(s), on the other hand, can be enqueued and their referents reclaimed in the same GC cycle, can't they?

I experimented with moving cleanup logic into VM [1],

What's the downside of that approach? I mean, why is GC-assisted approach better? Simpler?

but Peter Levart came up with a clever idea and implemented FinalReference-based cleaner-like Finalizator. Classes don't have finalizers, but Finalizator allows to attach a finalization action to them. And it is guaranteed that the referent is alive when finalization happens.

Also, Peter spotted another problem with Cleaner-based implementation. Cleaner cleanup action is strongly referenced, since it is registered in Cleaner class. CallSite context cleanup action keeps a reference to CallSite class (it is passed to MHN.invalidateDependentNMethods). Users are free to extend CallSite and many do so. If a context class and a call site class are loaded by a custom class loader, such loader will never be unloaded, causing a memory leak. Finalizator doesn't suffer from that, since the action is referenced only from Finalizator instance. The downside is that cleanup action can be missed if Finalizator becomes unreachable. It's not a problem for CallSite context, because a context is always referenced from some CallSite and if a CallSite becomes unreachable, there's no need to perform a cleanup. Testing: jdk/test/java/lang/invoke, hotspot/test/compiler/jsr292 Contributed-by: plevart, vlivanov Best regards, Vladimir Ivanov PS: frankly speaking, I would move Finalizator from java.lang.ref to java.lang.invoke and call it Context, if there were a way to extend package-private FinalReference from another package :-)

Modules may have an answer for that. FinalReference could be moved to a
package (java.lang.ref.internal or jdk.lang.ref) that is not exported to the world and made public.

On the other hand, I don't see a reason why FinalReference couldn't be part of JDK public API. I know it's currently just a private mechanism to implement finalization which has issues and many would like to see it gone, but Java has learned to live with it, and, as you see, it can be a solution to some problems too ;-)

Regards, Peter

[1] http://cr.openjdk.java.net/~vlivanov/8079205/webrev.00



More information about the core-libs-dev mailing list