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
