On Tue, 11 Aug 2026 19:03:17 GMT, Shiv Shah <[email protected]> wrote:

>> The test fails intermittently with OutOfMemoryError under -Xcheck:jni 
>> -XX:+UseZGC (the original report also had -XX:+ZGenerational, which is gone 
>> since JEP 490). Reproduced at about 2%: 6 of 300 runs on four hosts, all
>> with the original signature.
>> 
>> GC logs from the failing runs show the 512m heap reaching 100% with ZGC in 
>> back-to-back allocation-stall collections that reclaim almost nothing, 
>> ending in the OOME while Allocator.helper grows its list. The sampling
>> agent holds jweaks on the sampled objects, which keeps the transient garbage 
>> alive until a major collection runs. The test's actual live set is only 
>> about 20MB.
>> 
>> Fix: bump the test heap from 512m to 1g.
>> 
>> Testing: 500 default-config runs at 1g all pass. The failing configuration 
>> at 1g (501 runs) had 2 OOME failures, about 0.4% vs 2% at 512m.
>> 
>> 
>> 
>> ---------
>> - [x] I confirm that I make this contribution in accordance with the 
>> [OpenJDK Interim AI Policy](https://openjdk.org/legal/ai).
>
> Shiv Shah has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   enable gc logging in the test

Thanks!

I dug deeper into this and have found that the problem is -Xcheck:jni and the 
`checked_jni_IsSameObject` function:

Without -Xcheck:jni, the code runs the normal `IsSameObject` on the jweak 
handles. `IsSameObject` is intentionally written to use the 
`resolve_no_keepalive`, which as the name suggests, makes sure that the resolve 
operation does not keep the resolved object alive. With -Xcheck:jni, this is 
replaced with `checked_jni_IsSameObject`, which contains this:

    IN_VM(
      /* This JNI function can be used to compare weak global references
       * to nullptr objects. If the handles are valid, but contain nullptr,
       * then don't attempt to validate the object.
       */
      if (obj1 != nullptr && jniCheck::validate_handle(thr, obj1) != nullptr) {
        jniCheck::validate_object(thr, obj1);
      }
      if (obj2 != nullptr && jniCheck::validate_handle(thr, obj2) != nullptr) {
        jniCheck::validate_object(thr, obj2);
      }
    )
    jboolean result = UNCHECKED()->IsSameObject(env,obj1,obj2);


`jniCheck::validate_handle` calls `JNIHandles::resolve_external_guard(obj)`, 
which is a resolve with "keepalive" semantics. So, the -Xcheck:jni causes the 
test code agent to artificially keep holding the registered objects alive, 
preventing the GC from clearing out the jweak handles to the otherwise dead 
objects.

-------------

PR Comment: https://git.openjdk.org/jdk/pull/32229#issuecomment-5436502776

Reply via email to