代码之家  ›  专栏  ›  技术社区  ›  Philippe Marschall

JVMTI类未准备

  •  0
  • Philippe Marschall  · 技术社区  · 3 年前

    我正在使用JVMTI编写一个本地Java代理,它遍历所有加载类的所有方法。不幸的是,许多课程似乎还没有准备好,因此 GetClassMethods 退货 JVMTI_ERROR_CLASS_NOT_PREPARED 。我正在注册 ClassPrepare 事件回调,但似乎只对极少数类调用。简化后(减去所有错误处理和释放),我的代码如下所示

    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。我确实尝试注册了一个类准备回调,使用:

    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);
    

    但这只适用于极少数课程。

    我如何让JVM准备加载的类,以便 GetClassMethods 退货 JVMTI_ERROR_NONE ?

    到目前为止,我只使用JDK17.0.1和Shenandoah GC进行了测试。

    0 回复  |  直到 3 年前
        1
  •  3
  •   apangin    3 年前

    当某些类已加载但未加载时,这是正常情况 linked 。您不需要做任何事情来手动准备类——JVM会在需要时自动完成这项工作。JVM规范保证类在初始化之前已完全准备好。一旦发生这种情况,JVM TI ClassPrepare 事件被激发。

    所以为了获得所有可用的 jmethodID s您需要:

    1. 遍历所有加载的类,忽略可能的 JVMTI_ERROR_CLASS_NOT_PREPARED .
    2. 设置 ClassPrepare 事件回调和调用 GetClassMethods 在里面。
    推荐文章