私は、さまざまなタスクのためにいくつかの無関係な場所で JNI を使用している非常に大規模で複雑な C++ アプリケーションに取り組んでいます。プラットフォームは 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_;
ここで、このメソッドを呼び出す前に別の場所で JVM が作成された場合、その結果、JNI_GetCreatedJavaVMs() への呼び出しは JVM ポインターを返し、GetEnv() への呼び出しは JNI_OK を返し、有効に見えるポインターで jenv_ を更新します。ここまでは順調ですね。ただし、次に行うとき:
jclass javaClass = jenv_->FindClass(className);
例外がスローされます。stderr が /dev/null にリダイレクトされるため、例外自体からデータを取得できません。したがって、ExceptionDescribe() を呼び出すと、出力が地獄になります。例外オブジェクトを調べるには、FindClass("Throwable") を呼び出すための有効な JNI が必要なので、それも機能しません。
最初の JVM を作成しているときに正常に動作するため、FindClass() の呼び出しは適切です。
私がここでどこかで犯したに違いないばかげた間違いを見つけるのを手伝ってくれる人はいますか? ありがとう、ユヴァル。