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
