我正在开发一个非常庞大且复杂的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时,它工作正常。
任何人都可以帮我找到我必须在某处做过的愚蠢错误吗? 谢谢, 尤瓦。
答案 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
”。