保持对JNIEnv环境的全局引用

wes*_*ton 36 c java-native-interface jnienv

我JNIEnv在全局存储,所以我稍后可以调用静态java方法.但是存储一个全局指针是否是必要的JNIEnv,它们可以与任何其他java对象一起存储,或者它是一个不需要它的特殊情况.

JNIEnv* globalEnvPointer;

[JNICALL etc] void init(JNIENv* env, [etc])
{
   //required?
   globalEnvPointer = (JNIENv*) (env*)->GetGlobalRef(env, env);
   //or is this OK?
   globalEnvPointer = env;
}
Run Code Online (Sandbox Code Playgroud)

编辑

我在这里有点愚蠢,将使用的所有方法globalEnvPointer都在我的init中调用,因为我init实际上是我的c程序main方法,直到程序结束才会返回.我也在c程序中没有使用其他线程.我认为这简化了答案.

JNIEnv* globalEnvPointer;

[JNICALL etc] void main(JNIENv* env, [etc])
{
   //required?
   globalEnvPointer = (JNIENv*) (env*)->GetGlobalRef(env, env);
   //or is this OK?
   globalEnvPointer = env;
   someMethod();
}

void someMethod()
{
   //use globalEnvPointer here
}
Run Code Online (Sandbox Code Playgroud)

mab*_*aba 52

您无法缓存JNIEnv指针.在这里阅读:

JNI接口指针(JNIEnv)仅在当前线程中有效.如果另一个线程需要访问Java VM,它必须首先调用AttachCurrentThread()以将自身附加到VM并获取JNI接口指针.一旦连接到VM,本机线程就像在本机方法中运行的普通Java线程一样工作.本机线程保持连接到VM,直到它调用DetachCurrentThread()来分离自身.

你可以做的是缓存JavaVM指针.

static JavaVM *jvm;

[JNICALL etc] void init(JNIENv* env, [etc])
{
   jint rs = (*env)->GetJavaVM(env, &jvm);
   assert (rs == JNI_OK);
}
Run Code Online (Sandbox Code Playgroud)

然后,无论什么时候你需要JNIEnv指针来自没有给出它的上下文,你可以这样做:

void someCallback() {
    JNIEnv *env;
    jint rs = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
    assert (rs == JNI_OK);
    // Use the env pointer...
}
Run Code Online (Sandbox Code Playgroud)

但是无论何时从Java调用本机方法,都会给出使用的env指针:

JNIEXPORT jint JNICALL Java_package_Class_method(JNIEnv *env, jobject obj) {
    // just use the env pointer as is.
}
Run Code Online (Sandbox Code Playgroud)

  • @maba:OP可能需要一个单独的init函数,但也许他根本不知道JNI_OnLoad的存在.它只是扩展了答案.它并不意味着作为评论家,就像一个友好的小延伸暗示.我不写自己的答案,因为我认为你的答案已经很好,你应该得到积分.但是,也要考虑其他人阅读你的答案,而不仅仅是OP,并且有经验丰富且没有经验的人. (3认同)