JVMTI RetransformClasses() 花费了大量时间
JVMTI RetransformClasses() is taking a lot of time
我部署了一个简单的 JVMTI 代理来测试字节码检测。我的策略是在 CompiledMethodLoad
回调中调用 RetransformClasses
函数来调用 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
事件正常工作,但是当我只是在其中传递相同的 class 时需要花费很多时间。我的 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");
}
回答我的问题:
No. I wasn't doing anything wrong. It's supposed to take that much overhead.
证明如下:
我使用 Jitwatch 来了解问题。我分析了 ClassLoad
时间检测和 JIT 调用后的检测。我在这两种情况下都使用相同的应用程序代码。
Class 加载时间检测
执行时间: 约 18 秒
JIT 调用期间的检测
执行时间:约80秒
结论
我们可以在这里清楚地看到,当我尝试通过在 CompiledLoadEvent
中调用 RetransformClasses
-> CLassFileLoadHook
序列来检测我的代码时,JIT 只是停止,然后再也不会为我尝试检测的功能。之后它甚至不进行 OSR 编译。我在这篇. The follow up question is given 中总结了JIT这种行为的原因。欢迎任何知道解决方法的人回答。
我部署了一个简单的 JVMTI 代理来测试字节码检测。我的策略是在 CompiledMethodLoad
回调中调用 RetransformClasses
函数来调用 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
事件正常工作,但是当我只是在其中传递相同的 class 时需要花费很多时间。我的 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");
}
回答我的问题:
No. I wasn't doing anything wrong. It's supposed to take that much overhead.
证明如下:
我使用 Jitwatch 来了解问题。我分析了 ClassLoad
时间检测和 JIT 调用后的检测。我在这两种情况下都使用相同的应用程序代码。
Class 加载时间检测
执行时间: 约 18 秒
JIT 调用期间的检测
执行时间:约80秒
结论
我们可以在这里清楚地看到,当我尝试通过在 CompiledLoadEvent
中调用 RetransformClasses
-> CLassFileLoadHook
序列来检测我的代码时,JIT 只是停止,然后再也不会为我尝试检测的功能。之后它甚至不进行 OSR 编译。我在这篇