JVMTI class 未准备好
JVMTI class not prepared
我正在使用 JVMTI 编写本机 Java 代理,它遍历所有加载的 classes 的所有方法。不幸的是,许多 classes 似乎还没有准备好,因此 GetClassMethods
returns JVMTI_ERROR_CLASS_NOT_PREPARED
。我正在注册一个 ClassPrepare
事件回调,但似乎只有很少的 class 会被调用。简化(减去所有错误处理和释放)我的代码看起来像这样
JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* jvm, char *options, void *reserved) {
jvmtiEnv *jvmti;
jint class_count;
jclass* classes;
jint method_count;
jmethodID* methods;
(*jvm)->GetEnv(jvm, (void**) &jvmti, JVMTI_VERSION_11);
(*jvmti)->GetLoadedClasses(jvmti, &class_count, &classes);
for (int i = 0; i < class_count; i++) {
jclass klass = classes[i];
// here a lot of time JVMTI_ERROR_CLASS_NOT_PREPARED is returned
jvmtiError err = (*jvmti)->GetClassMethods(jvmti, klass, &method_count, &methods);
}
代理使用 JCMD 和 JVMTI.agent_load 命令动态附加到 运行 JVM。我确实尝试使用以下方式注册 class 准备回调:
jvmtiEventCallbacks callbacks;
(void)memset(&callbacks, 0, sizeof(callbacks));
callbacks.ClassPrepare = &callbackClassPrepare;
(*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint) sizeof(callbacks));
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, (jthread) NULL);
但这结束只被调用了很少 classes。
如何让 JVM 准备加载的 classes 以便 GetClassMethods
returns JVMTI_ERROR_NONE
?
到目前为止,我只用 JDK 17.0.1 和 Shenandoah GC 进行了测试。
加载了一些 类 但未加载 linked 时,这是正常情况。您无需执行任何操作来手动准备 类 - JVM 会在需要时自动执行此操作。 JVM 规范保证 类 在初始化之前已完全准备好。一旦发生,JVM TI ClassPrepare
事件就会被触发。
因此,为了获得所有可用的 jmethodID
,您需要:
- 迭代所有已加载的 类,忽略可能的
JVMTI_ERROR_CLASS_NOT_PREPARED
。
- 设置
ClassPrepare
事件回调并在其中调用GetClassMethods
。
我正在使用 JVMTI 编写本机 Java 代理,它遍历所有加载的 classes 的所有方法。不幸的是,许多 classes 似乎还没有准备好,因此 GetClassMethods
returns JVMTI_ERROR_CLASS_NOT_PREPARED
。我正在注册一个 ClassPrepare
事件回调,但似乎只有很少的 class 会被调用。简化(减去所有错误处理和释放)我的代码看起来像这样
JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* jvm, char *options, void *reserved) {
jvmtiEnv *jvmti;
jint class_count;
jclass* classes;
jint method_count;
jmethodID* methods;
(*jvm)->GetEnv(jvm, (void**) &jvmti, JVMTI_VERSION_11);
(*jvmti)->GetLoadedClasses(jvmti, &class_count, &classes);
for (int i = 0; i < class_count; i++) {
jclass klass = classes[i];
// here a lot of time JVMTI_ERROR_CLASS_NOT_PREPARED is returned
jvmtiError err = (*jvmti)->GetClassMethods(jvmti, klass, &method_count, &methods);
}
代理使用 JCMD 和 JVMTI.agent_load 命令动态附加到 运行 JVM。我确实尝试使用以下方式注册 class 准备回调:
jvmtiEventCallbacks callbacks;
(void)memset(&callbacks, 0, sizeof(callbacks));
callbacks.ClassPrepare = &callbackClassPrepare;
(*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint) sizeof(callbacks));
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, (jthread) NULL);
但这结束只被调用了很少 classes。
如何让 JVM 准备加载的 classes 以便 GetClassMethods
returns JVMTI_ERROR_NONE
?
到目前为止,我只用 JDK 17.0.1 和 Shenandoah GC 进行了测试。
加载了一些 类 但未加载 linked 时,这是正常情况。您无需执行任何操作来手动准备 类 - JVM 会在需要时自动执行此操作。 JVM 规范保证 类 在初始化之前已完全准备好。一旦发生,JVM TI ClassPrepare
事件就会被触发。
因此,为了获得所有可用的 jmethodID
,您需要:
- 迭代所有已加载的 类,忽略可能的
JVMTI_ERROR_CLASS_NOT_PREPARED
。 - 设置
ClassPrepare
事件回调并在其中调用GetClassMethods
。