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).

While working on this PR I've learned quite a bit more about how the debug 
agent and JDI manage ObjectIDs, and I think I now have an idea for a more 
complete and much simpler solution. It would cover all the APIs that allocate, 
and would not require any spec changes, JDI implementation changes, or debugger 
changes.

The only changes would be in the debug agent, and they would be similar to what 
I already have in place in this PR for the invoker support, which is to do a 
commonRef_pin() on the object, although with this new approach we always do the 
commonRef_pin(), not conditional on the INVOKE_DISABLE_COLLECTION flag being 
set. The same would be done when allocating a String or array.

Why does this work out ok? First I should point out that pinning in this manner 
keeps the object live until something triggers an unpin. What that means is 
that if the JDI users gets back an allocated object, does something to force a 
GC on the debuggee, and then calls ObjectReference.isCollected(), false will be 
returned, whereas currently it would return true. However, I'm not so sure 
there is anything in the spec that requires that behavior, but I'm guessing it 
might cause some tests to fail. In fact the test I wrote for the PR would fail 
since it does exactly that as a sanity check (allocate without pinning, force 
debuggee GC, verify isCollected).

There is also the question of whether or not this keeps the object live for 
longer than we would like. There are 3 reasons this issue is largely mitigated:

(1) The most obvious is that the JDI user should already be calling 
ObjectReference.disableCollection() as soon as the object is returned, and then 
call enableCollection() when done. The enableCollection() will see the 
gcDisableCount go to 0, and call ObjectReference.EnableCollection, which will 
result in the object being unpinned. So in the normal use case the life of the 
pin is not being extended beyond any current pinning.

(2) There is one other safety net to the possibility of an indefinite pin. JDI 
keeps track of all ObjectReferences using a ReferenceQueue. When the 
ObjectReferences is collected, its ObjectID is added to a list that eventually 
gets passed to JDWP VirtualMachine.DisposeObject. This will dispose of the 
ObjectID (meaning disposing of the RefNode that is tracking it) even if it is 
pinned. It will also release the strong reference if it is pinned.

(3) Detaching from the debug agent unpins all objects.

BTW, this is similar to the suggestion to set a global pinning flag using 
VirtualMachine.DisableCollection or similar. The main difference is not having 
the JDI side increment gcDisableCount.

If we agree there are no spec issues with this approach, I can implement it 
pretty easily.

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

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

Reply via email to