Подтвердить что ты не робот

Сохранение глобальной ссылки на среду 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;
}

Edit

Я немного тупой здесь, все методы, которые будут использовать globalEnvPointer, вызываются в моем init, потому что мой init на самом деле мой метод c program 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
}
4b9b3361

Ответ 1

Вы не можете кэшировать указатель JNIEnv. Читайте об этом здесь:

Указатель интерфейса JNI (JNIEnv) действителен только в текущем потоке. Если другой поток должен получить доступ к виртуальной машине Java, он должен сначала вызвать AttachCurrentThread() для присоединения к виртуальной машине и получения указателя интерфейса JNI. После присоединения к виртуальной машине собственный поток работает так же, как обычный поток Java, запущенный внутри собственного метода. Нативный поток остается прикрепленным к виртуальной машине до тех пор, пока он не вызовет DetachCurrentThread(), чтобы отсоединить себя.

Что вы можете сделать, это кэшировать указатель JavaVM.

static JavaVM *jvm;

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

И тогда, когда вам понадобится указатель JNIEnv из контекста, где он не указан, вы делаете это:

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

Но всякий раз, когда вы вызываете собственный метод из Java, указывается указатель env для использования:

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