获取有效的JNI环境指针

时间:2013-05-30 13:15:52

标签: java-native-interface

我正在开发一个非常庞大且复杂的C ++应用程序,它在几个不相关的地方使用JNI来完成不同的任务。该平台是RHEL 6.因为我不知道应用程序是否已经创建了JNI,我使用此方法来查找JVM并附加到它:

JOI_RetCode JavaObjectInterface::initJVM()
{
  if (jvm_ == NULL)
  {
    // Is there an existing JVM already created?
    jsize jvm_count = 0;
    jint result = JNI_GetCreatedJavaVMs (&jvm_, 1, &jvm_count);
    if (result != JNI_OK)
      return JOI_ERROR_CHECK_JVM;      

    if (jvm_count == 1)
    {
      // Yes - use it.
      result = jvm_->GetEnv((void**) &jenv_, JNI_VERSION_1_6);
      switch (result)
      {
        case JNI_OK:
          logger::log(CAT_JNI, LL_DEBUG, "Attached to an existing JVM.");
          jenv_ = env;
          break;

        case JNI_EDETACHED:
          result = jvm_->AttachCurrentThread((void**) &jenv_, NULL);   
          if (result != JNI_OK)
            return JOI_ERROR_ATTACH_JVM;

          needToDetach_ = true;
          logger::log(CAT_JNI, LL_DEBUG, "Attached to an existing JVM from another thread.");
          break;

        case JNI_EVERSION:
          logger::log(CAT_JNI, LL_DEBUG, "Attaching to a JVM of the wrong version.");
          return JOI_ERROR_JVM_VERSION;
          break;

        default:
          logger::log(CAT_JNI, LL_DEBUG, "Unknown error Attaching to an existing JVM.");
          return JOI_ERROR_ATTACH_JVM;
          break;
      }
    }
    else
    {
      // No - create a new one.
      result = createJVM();
      if (result != JNI_OK)
        return JOI_ERROR_CREATE_JVM;

      needToDetach_ = false;
      logger::log(CAT_JNI, LL_DEBUG, "Created a new JVM.");
    }
  }

  return JOI_OK;
}

JVM指针定义为类数据成员,如下所示:

JavaVM*   jvm_;
JNIEnv*   jenv_;

现在,当我在调用thid方法之前在别处创建JVM时,结果是对JNI_GetCreatedJavaVMs()的调用返回JVM指针,对GetEnv()的调用返回JNI_OK,并使用指向外观的指针更新jenv_有效。到现在为止还挺好。但是,当我接下来做的时候:

  jclass javaClass = jenv_->FindClass(className); 

我抛出异常。我无法从异常本身获取任何数据,因为stderr被重定向到/ dev / null,所以如果我调用ExceptionDescribe(),输出就会变成地狱。询问异常对象需要一个工作的JNI来调用FindClass(“Throwable”),因此它也不起作用。

对FindClass()的调用很好,因为当我创建第一个JVM时,它工作正常。

任何人都可以帮我找到我必须在某处做过的愚蠢错误吗? 谢谢, 尤瓦。

1 个答案:

答案 0 :(得分:2)

JNIEnv指针通常是特定于线程的。最简单的方法就是使用JVM引用按需查找。

对于需要访问JNIEnv的任何代码块,请在该本地块的范围内查找:

JNIEnv* jenv_;
int result = jvm_->GetEnv((void**) &jenv_, JNI_VERSION_1_6);
if (result == JNI_EDETACHED) {
    // attach
}
// Do what you gotta do here
// ...
if (needs_detach) {
    // detach
}

这样,无论您的背景如何,您都会确保获得有效的JNIEnv

这方面的主要内容是“不要缓存JNIEnv”。