On Mon, 8 Jun 2026 14:44:49 GMT, Chris Plummer <[email protected]> wrote:

> The PR resolves the issue JDI has with allowing collection of objects that 
> are returned by the JDI invoke API before the caller of the API has a chance 
> to call ObjectReference.disableCollection(). Details in the first comment.
> 
> Consider this to be a prototype. I'm open to discussion on other possible 
> solutions. I also still need to update the JDI specs to reflect these changes.
> 
> ---------
> - [x] I confirm that I make this contribution in accordance with the [OpenJDK 
> Interim AI Policy](https://openjdk.org/legal/ai).

The core issue here is that with modern collectors it is becoming more and more 
common for returned newly allocated objects to be collected before the debugger 
can call ObjectReference.disableCollection(). Historically JDI has assumed that 
since at the very least the thread used to do the invoke on has been suspended, 
a GC could not happen. That hasn't been true for a very long time, even with 
all threads suspended, and has resulted in ObjectCollectedExceptions turning up 
in many of our tests. These were for the most part test bugs since they never 
called ObjectReference.disableCollection(), but even if they do, there is still 
a chance of the object being collected before the call is made, and this is an 
issue for debuggers. Modern GCs have made this problem even worse.

The main JDI APIs involved are following, all of which use the JDI invoker 
support (using JDI to invoke a method on the target JVM):

- ObjectReference.invokeMethod()
- ClassType.invokeMethod()
- InterfaceType.invokeMethod()
- ClassType.newInstance()

Also the following two APIs, which currently are not addressed by this PR. 
These do not use the invoke API.

- VirtualMachine.mirrorOf(String), which uses JDWP VirtualMachine.CreateString
- ArrayType.newInstance

The APIs which use the JDI invoke API can all be fixed by adding a new invoke 
flag called INVOKE_DISABLE_COLLECTION. This is in addition to the existing 
INVOKE_SINGLE_THREADED and INVOKE_NONVIRTUAL flags. This is what has been 
implemented in this PR.

So the first question is whether this approach should be the one used, and if 
yes, how should we address the other two APIs. Most debuggers are already doing 
working around this issue by putting array and String allocation in a retry 
loop until ObjectReference.disableCollection() succeeds. This is not so bad 
since these APIs don't have side affects unlike the invoke APIs do. We could 
also create something like ArrayType.newInstanceDisableCollection, although the 
naming gets awkward. It's also easy to create JDWP 
VirutualMachine.CreateStringDisableCollection, but we would then need something 
like VirtualMachine.mirrorOf(String, boolean disableCollection) in order to use 
it from JDI. 

Another possible solution that would cover all 6 of these allocation API is to 
add a new API called something like VirtualMachine.DisableCollection. The name 
as given is a bit misleading. It would only disable collection on any 
ObjectReference returned by the above APIs. It's a bit risky, because the user 
may not be aware of all these API and possibly end up with memory leaks due to 
forgetting to call objectreference.enablecollection() (note, once the debugger 
detaches the references are released and the objects can be collected). We 
could also limit its use to allocated arrays and Strings, and leave the 
INVOKE_DISABLE_COLLECTION flag for when using the invoke APIs.

And one more thing to point out about the INVOKE_DISABLE_COLLECTION flag. It 
not only impacts the returned ObjectReference, but if an exception is thrown, 
it disables collection on the ObjectReference representing the actual exception 
Object thrown. It is stored in the InvocationException object. So users need to 
be aware that if they use this flag and an exception is thrown, they need to 
call disableCollection() on the exception object or it won't be collected. We 
could use a different flag for the exception if desirable. The flags could be 
called something like INVOKE_DISABLE_COLLECTION_ON_RETURNED_OBJECT and 
INVOKE_DISABLE_COLLECTION_ON_EXCEPTION_OBJECT)

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

PR Comment: https://git.openjdk.org/jdk/pull/31421#issuecomment-4650222280

Reply via email to