The debug agent needs to keep track of all loaded classes, and also be notified when they are unloaded. It tracks classes loading by getting CLASS_PREPARE events and it tracks their unloading by tagging them, which triggers OBJECT_FREE events when they are unloaded. The tagging and OBJECT_FREE events are handled by a separate JVMTIEnv from the one that does main event handling, mostly in support of the attached debugger. However, the CLASS_PREPARE events are piggy backed on the main event handler. As a result, we have this special check in filterAndHandleEvent():
/* We must keep track of all classes prepared to know what's unloaded */
if (evinfo->ei == EI_CLASS_PREPARE) {
classTrack_addPreparedClass(env, evinfo->clazz);
}
We also have to always keep CLASS_PREPARE events enabled on the main event handler, even if the debugger is not requesting them. The main event handler has a lot of overhead that isn't necessary when simply wanting to use the CLASS_PREPARE event for class tracking.
Another downside of this piggy backing is it causes problems for addressingJDK-8295376, which is attempting to not track virtual threads when the debugger is not attached (no VIRTUAL_THREAD_START and VIRTUAL_THREAD_END events). The problem is when the debugger is not attached and a CLASS_PREPARE event comes in on a virtual thread, the debug agent unnecessarily creates a ThreadNode for it. Since there won't be a corresponding VIRTUAL_THREAD_END event when the virtual thread is destroyed (as long as the debugger is not attached), the debug agent ends up keeping this ThreadNode around even after the thread is gone. This usually eventually leads to an assert.
The fix for this is pretty simple. We already have the separate JVMTIEnv that the class tracker uses to handle OBJECT_FREE. This is easily purposed to also handle CLASS_PREPARE events. By doing so we can get rid of the special CLASS_PREPARE code above in filterAndHandleEvent(), and we also only need to enable CLASS_PREPARE events for the main event handler when a debugger is attached and is requesting them.
/* We must keep track of all classes prepared to know what's unloaded */
if (evinfo->ei == EI_CLASS_PREPARE) {
classTrack_addPreparedClass(env, evinfo->clazz);
}
We also have to always keep CLASS_PREPARE events enabled on the main event handler, even if the debugger is not requesting them. The main event handler has a lot of overhead that isn't necessary when simply wanting to use the CLASS_PREPARE event for class tracking.
Another downside of this piggy backing is it causes problems for addressing
The fix for this is pretty simple. We already have the separate JVMTIEnv that the class tracker uses to handle OBJECT_FREE. This is easily purposed to also handle CLASS_PREPARE events. By doing so we can get rid of the special CLASS_PREPARE code above in filterAndHandleEvent(), and we also only need to enable CLASS_PREPARE events for the main event handler when a debugger is attached and is requesting them.
- relates to
-
JDK-8295815 misc JDI tests failed with "JDWP exit error JVMTI_ERROR_WRONG_PHASE(112)"
-
- Resolved
-
-
JDK-8295376 Improve debug agent virtual thread performance when no debugger is attached
-
- Resolved
-
-
JDK-8295814 jdk/jshell/CommandCompletionTest.java fails with "lists don't have the same size expected [2] but found [1]"
-
- Resolved
-
-
JDK-8295816 jdwp jck tests failing with "FATAL ERROR in native method: JDWP SetTag, jvmtiError=JVMTI_ERROR_WRONG_PHASE(112)"
-
- Resolved
-
(1 links to)