Summary
The parameters to the JVMTI Extension event ClassUnload
are JNIEnv*
, java.lang.Thread
, and java.lang.Class
of the class being unloaded. The last two arguments are buggy, are replaced with char*
, which is the name of the class.
Problem
The java.lang.Thread
argument is not the thread that requested the event. In stop-the-world GCs, at least the target thread is stopped while the event unsafely modifies the state, in order to send the event to the Java thread that can call JNI. The user can't access the java.lang.Thread
object without going into JNI, which will not continue while a safepoint is in progress, so will hang.
The java.lang.Class
argument is the Java Object that is not marked during GC, so not live. This parameter returns a dead object to the caller.
This doesn't work at all for GCs like ZGC.
Solution
Replacing the last two arguments with C char*
argument, which gives the name of the class being unloaded. So it's a more useful event. The purpose for the extension event is primarily to test the extension event mechanism. There are better ways in JVMTI to find out if your class is unloaded.
There used to be a JVMTI ClassUnload event that was removed in 2003 by https://bugs.openjdk.java.net/browse/JDK-4898113 and the JPDA release in 1.5 never included it. The ClassUnload event was changed to the extension event as a demonstration of the extension event mechanism but it looks like the arguments and code were kept.
IBM implements several different extension events which are documented in some obsolete references online, but ClassUnload appears not to be one of them.
Specification
I could not find anything online that specifies the format of the JVMTI ClassUnload
Extension event. The arguments came from the ClassUnload
event that was removed from the specification because it was buggy.
static jvmtiParamInfo event_params[] = {
- { (char*)"JNI Environment", JVMTI_KIND_IN, JVMTI_TYPE_JNIENV, JNI_FALSE },
- { (char*)"Thread", JVMTI_KIND_IN, JVMTI_TYPE_JTHREAD, JNI_FALSE },
- { (char*)"Class", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, JNI_FALSE }
+ { (char*)"JNI Environment", JVMTI_KIND_IN_PTR, JVMTI_TYPE_JNIENV, JNI_FALSE },
+ { (char*)"Class", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CCHAR, JNI_FALSE }
};
static jvmtiExtensionEventInfo ext_event = {
EXT_EVENT_CLASS_UNLOAD,
(char*)"com.sun.hotspot.events.ClassUnload",
(char*)"CLASS_UNLOAD event",
sizeof(event_params)/sizeof(event_params[0]),
event_params
};
- csr of
-
JDK-8260002 JvmtiExport::post_class_unload() is broken for non-JavaThread initiators
- Resolved