JDK-8075259 : JVMTI: Class initialization generates MonitorWaited without matched MonitorWait
  • Type: Bug
  • Component: hotspot
  • Sub-Component: jvmti
  • Affected Version: 8u40,9
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2015-03-16
  • Updated: 2025-06-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 26
26Unresolved
Related Reports
Relates :  
Relates :  
Relates :  
Description
When JVM waits on a class loading lock, JVMTI_EVENT_MONITOR_WAITED is posted, but the corresponding JVMTI_EVENT_MONITOR_WAIT is not.

Though JVMTI Spec does not strictly prescribe when these events should occur (see JDK-6455295), the common sense suggests that whenever an object waiting happens either both events should be posted or none at all.

Here is an example to demonstrate the issue:
(java -agentlib:monitorWaitAgent MonitorWait)

// MonitorWait.java
public class MonitorWait {
    
    public static void main(String[] args) {
        new Thread(Parent::new).start();
        new Child();
    }
 
    static class Parent {
        static {
            try {
                Thread.sleep(200);
            } catch (Exception e) { /* ignore */ }
        }
    }

    static class Child extends Parent {
    }
}

// monitorWaitAgent.c
#include <jvmti.h>
#include <string.h>
#include <stdio.h>

void JNICALL MonitorWait(jvmtiEnv* jvmti, JNIEnv* env, jthread thread, jobject object, jlong timeout) {
    printf("> MonitorWait\n");
}

void JNICALL MonitorWaited(jvmtiEnv* jvmti, JNIEnv* env, jthread thread, jobject object, jboolean timed_out) {
    printf("< MonitorWaited\n");
}

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
    jvmtiEnv* jvmti;
    jvmtiEventCallbacks callbacks;
    jvmtiCapabilities capabilities;

    (*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_2);

    memset(&capabilities, 0, sizeof(capabilities));
    capabilities.can_generate_monitor_events = 1;
    (*jvmti)->AddCapabilities(jvmti, &capabilities);

    memset(&callbacks, 0, sizeof(callbacks));
    callbacks.MonitorWait = MonitorWait;
    callbacks.MonitorWaited = MonitorWaited;
    (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
    (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAIT, NULL);
    (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAITED, NULL);
    
    printf("Agent loaded\n");
    return 0;
}

Comments
Targeted to tbd. It was temporarily targeted to 14 for evaluation to keep it on my radar.
29-10-2019

As discussed in 6501158 these JVMTI events pertain to calls to Object.wait() and in the class initialization process we are not calling Object.wait() and so arguably none of the events should be posted. That is probably less confusing than posting events for a monitor which may not be associated with a Java Object (even though it presently is). But I'm not averse to changing this in Java 9 (or 10), based on the use of the int[0] object, if there is sufficient motivation. 6501158 was closed because nobody really cared about such details (even though people do occasionally still run into them).
17-03-2015

The problem is caused by the asymmetry in the code: MONITOR_WAIT is posted from JVM_MonitorWait, while MONITOR_WAITED is generated from ObjectMonitor::wait. The class initialization procedure calls ObjectMonitor::wait directly from VM. It is discussable whether these events should be generated for a class loading lock - at least, the following comment for JDK-6380127 is wrong: << Note further that we do not perform any JVMTI event processing around this particular "wait" >> I would prefer to generate both events, as well as to change Java thread state correspondingly (see JDK-6501158), otherwise it makes class initialization deadlocks confusing and difficult to debug, see http://stackoverflow.com/questions/28631656/runnable-thread-state-but-in-object-wait
16-03-2015