On Mon, 9 Feb 2026 at 15:04, Jochen Theodorou <[email protected]> wrote:
>
> On 02.02.26 17:50, Chris Dennis wrote:
> > Hi All,
> >
> > I've been dealing with sporadic failures of Groovy based tests with
> > false overload disambiguation issues when running on OpenJ9 with `-
> > Xsoftrefthreshold0` - this essentially turns soft references into weak
> > references - they get cleared very quickly. The cause for my failures
> > appears to be that Groovy is relying on referential equality (or
> > inequality) between CachedClass instances to infer things about the
> > associated Java class relationship. My logging though shows that the
> > mapping here isn't truly canonical though - at least not under OpenJ9 in
> > this configuration. I'm seeing instances where the runtime is comparing
> > two different instances of CachedClass derived from the same ClassInfo
> > and falsely inferring that the two classes are distinct and therefore
> > populating method caches with duplicate method instances and giving me
> > false ambiguous overload failures.
>
>
> I don't quite understand... the ClassInfo holds the reference to
> ChachedClass and creates it lazy... so maybe what happens is that the
> lazy mechanism is not 100% right and two CachedClass instances are created?

The lazy mechanism is working correctly - the problem is that the
lazily created instances are only softly-referenced which means the GC
can come along later and clean that reference, and then a newly
arriving thread will create an additional instance of CachedClass for
the same type. If/when those two instances then meet they will falsely
compare not-equal and the Groovy runtime will think they represent
different types (which they don't). I think the fix here is to
implement (and use) an equals method for CachedClass which uses this
referential comparison but only as an optimistic fast path. (There is
another theoretical fix here where all accesses of a given CachedClass
are always mediated through a single SoftReference, which I think
would make the existing scheme safe, but I fear it would be overly
brittle).
>
>
> > I'm attempting to narrow down how exactly this is happening and whether
> > the cause is OpenJ9 incorrectly clearing a soft reference to a strongly
> > reachable instance, or is due to Groovy missing one or more
> > reachabilityFences to prevent early clearing of these references.
>
> Can you verify other JVMs as well?

I've not been able to reproduce this on anything other than OpenJ9 -
which I suspect is due to OpenJ9 being much more eager to clear
references. I'm pretty sure I have a valid mechanism through which it
can happen though - it just seems to be impossible to make Hotspot
trigger it (so far).

>
> > Looking forward to peoples insights and/or thoughts on how best to
> > approach this. A simple fix would be to only rely on referential
> > (in)equality for a fast path check, with fallback to a more robust
> > check. Alternatively, the (much harder) but likely cleaner path is to
> > fix the underlying Groovy and/or OpenJ9 bug. Note that if this is a
> > Groovy bug around reachability then I don't think it's safe to assume
> > that this cannot happen on Hotspot either now, or in the future if/when
> > GC behavior there changes
>
> ideally we fix the bug in Groovy, if it is in Groovy. I highly doubt all
> JVMs have this problem if it is from the JVM
>
> bye Jochen

Reply via email to