保持对JNIEnv环境的全局引用。

时间:2020-12-30 23:36:09

I am storing off JNIEnv in a global so I can call static java methods later. But is it nessasary to store off a global pointer to the JNIEnv, they way one would with any other java object, or is it a special case that does not require this.

我在全局中存储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;
}

Edit

编辑

I'm bing a bit dumb here, all the methods that will use globalEnvPointer, are invoked within my init because my init is actually my c program's main method, which won't return until the end of the program. I am also using no other threads in the c program. I think this simplifies the answer.

我在这里有点笨,所有使用globalEnvPointer的方法,都是在我的init中调用的,因为我的init实际上是我的c程序的主方法,在程序结束之前不会返回。我也没有在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
}

1 个解决方案

#1


42  

You cannot cache the JNIEnv pointer. Read about it here:

不能缓存JNIEnv指针。读到这里:

The JNI interface pointer (JNIEnv) is valid only in the current thread. Should another thread need to access the Java VM, it must first call AttachCurrentThread() to attach itself to the VM and obtain a JNI interface pointer. Once attached to the VM, a native thread works just like an ordinary Java thread running inside a native method. The native thread remains attached to the VM until it calls DetachCurrentThread() to detach itself.

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

What you can do is to cache the JavaVM pointer instead.

您可以做的是缓存JavaVM指针。

static JavaVM *jvm;

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

And then whenever you need then JNIEnv pointer from a context where it is not given you do this:

然后,无论何时你需要JNIEnv指针从一个没有给你的context中你可以这样做:

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

But whenever you call a native method from Java the env pointer to use is given:

但是,无论何时调用来自Java的本机方法,都将使用env指针:

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

#1


42  

You cannot cache the JNIEnv pointer. Read about it here:

不能缓存JNIEnv指针。读到这里:

The JNI interface pointer (JNIEnv) is valid only in the current thread. Should another thread need to access the Java VM, it must first call AttachCurrentThread() to attach itself to the VM and obtain a JNI interface pointer. Once attached to the VM, a native thread works just like an ordinary Java thread running inside a native method. The native thread remains attached to the VM until it calls DetachCurrentThread() to detach itself.

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

What you can do is to cache the JavaVM pointer instead.

您可以做的是缓存JavaVM指针。

static JavaVM *jvm;

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

And then whenever you need then JNIEnv pointer from a context where it is not given you do this:

然后,无论何时你需要JNIEnv指针从一个没有给你的context中你可以这样做:

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

But whenever you call a native method from Java the env pointer to use is given:

但是,无论何时调用来自Java的本机方法,都将使用env指针:

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