JVMTI RetransformClasses()花费了大量时间

时间:2016-12-26 07:22:20

标签: java performance jvm-hotspot bytecode-manipulation jvmti

我部署了一个简单的JVMTI代理来测试字节码检测。我的策略是在RetransformClasses回调中调用CompiledMethodLoad函数来调用ClassFileLoadHook。我写了以下代码:

    err = (*jvmti)->GetMethodDeclaringClass(jvmti, method, &klass);
    check_jvmti_error(jvmti, err, "Get Declaring Class");

    err = (*jvmti)->RetransformClasses(jvmti, 1, &klass);
    check_jvmti_error(jvmti, err, "Retransform class");

这个函数通过调用ClassFileLoadHook事件可以正常工作,但是当我在其中传递同一个类时需要花费很多时间。我的ClassFileLoadHook回调函数为空。我计算简单矩阵乘法算法的时间。通过注释掉RetransformClasses函数,我获得了0.8 seconds的执行时间。而只是编写此函数会将执行时间提升到15 seconds左右。

它应该花费那么多开销还是我做错了什么?

问候

代码:

static int x = 1;
void JNICALL
compiled_method_load(jvmtiEnv *jvmti, jmethodID method, jint code_size,
        const void* code_addr, jint map_length, const jvmtiAddrLocationMap* map,
        const void* compile_info) {
    jvmtiError err;
    jclass klass;

    char* name = NULL;
    char* signature = NULL;
    char* generic_ptr = NULL;

    err = (*jvmti)->RawMonitorEnter(jvmti, lock);
    check_jvmti_error(jvmti, err, "raw monitor enter");

    err = (*jvmti)->GetMethodName(jvmti, method, &name, &signature,
            &generic_ptr);
    check_jvmti_error(jvmti, err, "Get Method Name");

    printf("\nCompiled method load event\n");
    printf("Method name %s %s %s\n\n", name, signature,
            generic_ptr == NULL ? "" : generic_ptr);

    if (strstr(name, "main") != NULL && x == 1) {
        x++;
        err = (*jvmti)->GetMethodDeclaringClass(jvmti, method, &klass);
        check_jvmti_error(jvmti, err, "Get Declaring Class");

        err = (*jvmti)->RetransformClasses(jvmti, 1, &klass);
        check_jvmti_error(jvmti, err, "Retransform class");

    }

    if (name != NULL) {
        err = (*jvmti)->Deallocate(jvmti, (unsigned char*) name);
        check_jvmti_error(jvmti, err, "deallocate name");
    }
    if (signature != NULL) {
        err = (*jvmti)->Deallocate(jvmti, (unsigned char*) signature);
        check_jvmti_error(jvmti, err, "deallocate signature");
    }
    if (generic_ptr != NULL) {
        err = (*jvmti)->Deallocate(jvmti, (unsigned char*) generic_ptr);
        check_jvmti_error(jvmti, err, "deallocate generic_ptr");
    }

    err = (*jvmti)->RawMonitorExit(jvmti, lock);
    check_jvmti_error(jvmti, err, "raw monitor exit");
}

1 个答案:

答案 0 :(得分:0)

回答我的问题:

  

没有。我没有做错任何事。它应该承担那么多开销。

以下是证据:

我使用http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#how-to-enable-http-response-compression来深入了解问题。我在JIT调用后分析了ClassLoad时间检测和检测。我在两种情况下都使用相同的应用程序代码。

类加载时间检测

Jitwatch

执行时间:约18秒

JIT调用期间的工具

JIT invocation during class load time

执行时间:约80秒

结论

我们可以清楚地看到,当我尝试通过调用RetransformClasses - >来检测我的代码时CLassFileLoadHook中的CompiledLoadEvent序列,JIT只是暂停,然后永远不会被我试图检测的函数调用。之后它甚至都没有进行OSR编辑。我在这个JIT invocation during instrumentation after JIT is invoked 中总结了JIT这种行为的原因。后续问题是answer。任何知道解决方法的人都欢迎回答。