Question

Can anybody explain to me why can I get a callback when jvm allocates some java objects, but not others? Here is what I am doing:

static jvmtiCapabilities    capa;
static jvmtiEnv*            jvmti                   = NULL;
static const char*          fileName                = "C:\\temp\\ObjectInitCallbackDump.txt";
static ofstream             outFileStream;

void JNICALL callbackObjectAllocation ( jvmtiEnv*   jvmti_env, 
                                        JNIEnv*     jni_env,
                                        jthread     thread,
                                        jobject     object,
                                        jclass      object_klass,
                                        jlong       size            )
{
    char*       generic_ptr_class;
    char*       class_name;
    jvmtiError  error;

    error = jvmti_env->GetClassSignature(object_klass, &class_name, &generic_ptr_class);
    if (check_jvmti_error(jvmti_env, error, "Failed to get class signature")) {
        return;
    }
    outFileStream << class_name << std::endl;
}

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
    jint                result;
    jvmtiError          error;
    jvmtiEventCallbacks callbacks;

    outFileStream.open(fileName,ios::trunc);

    result  = jvm->GetEnv((void**) &jvmti, JVMTI_VERSION_1_1);
    if (result != JNI_OK || jvmti == NULL) {
        printf("error\n");
        return JNI_ERR;
    } else {
        printf("loaded agent\n");
    }

    (void) memset(&capa, 0, sizeof(jvmtiCapabilities));
    capa.can_generate_vm_object_alloc_events        = 1;

    error = jvmti->AddCapabilities(&capa);
    if (check_jvmti_error(jvmti, error, "Unable to set capabilities") != JNI_OK) {
        return JNI_ERR;
    }

    (void) memset(&callbacks, 0, sizeof(callbacks));
    callbacks.VMObjectAlloc         = &callbackObjectAllocation;

    error = jvmti->SetEventCallbacks(&callbacks, (jint) sizeof(callbacks));
    if (check_jvmti_error(jvmti, error, "Unable to set callbacks") != JNI_OK) {
        return JNI_ERR;
    }

    error = jvmti->SetEventNotificationMode(    JVMTI_ENABLE,
                                                JVMTI_EVENT_VM_OBJECT_ALLOC,
                                                (jthread) NULL);
    if (check_jvmti_error(jvmti, error,
            "Unable to set method entry notifications") != JNI_OK) {
        return JNI_ERR;
    }

    return JNI_OK;
}

JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) {
    outFileStream.close();
}

When I examine the file that I create, I do not see the classes that I am interested in, although I know they are there and NetBeans tells me there is exactly one instance of that class in the jvm. Any thoughts???

Nikita

Was it helpful?

Solution

For performance reasons, the JVMTI only supports allocation events for objects that cannot be detected through bytecode instrumentation (BCI), as explained in the JVMTI VMObjectAlloc event documentation. This means that the event will not be triggered for most object allocations. I assume that the allocations you are missing fall within that category.

Fortunately, it's not really too difficult to intercept all object allocations using BCI. The HeapTracker demo illustrates precisely how to intercept all object allocations in a JVMTI agent using java_crw_demo in addition to the VMObjectAlloc events.

OTHER TIPS

Maybe you are just not hitting your check? If this is the code you actually run then you have a bug; you missed the ; at the end of the object Your compare should be like this:

if (strcmp(class_name,"Ljavax/swing/JFrame;") == 0) {
    printf("Got the sucker!!!");
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top