返回在JNI中创建的对象时的NewGlobalRef / DeleteGlobalRef

时间:2015-04-27 09:07:48

标签: java android-ndk java-native-interface

当将对JNI方法创建的对象的引用返回给Java时,是否应该在创建的对象上返回NewGlobalRef调用的结果?而且,稍后,当Java中不再需要对象时,我们是否需要调用JNI方法对从Java传递的引用执行DeleteGlobalRef?

或者NewGlobalRef / DeleteGlobalRef只需要在JNI内部,JNI方法调用之间保存对Java对象的引用,如果我们只是将创建的对象返回给Java,我们不需要进行NewGlobalRef / DeleteGlobalRef调用吗?

我在一个大型开源项目中看到过这样的事情:

extern "C" JNIEXPORT jobject JNICALL
Java_foo_bar_Baz_create(JNIEnv* env, jclass, jint size) {
    void* buf = malloc(size);
    jobject obj = env->NewDirectByteBuffer(buf, size);
    return env->NewGlobalRef(obj);
}

extern "C" JNIEXPORT void JNICALL
Java_foo_bar_Baz_free(JNIEnv* env, jclass, jobject jbuffer) {
    void* buf = env->GetDirectBufferAddress(jbuffer);        
    free(buf);
}

它在创建的NewDirectByteBuffer对象上返回NewGlobalRef调用的结果,之后,当Java中不再需要对象时,调用JNI方法不调用DeleteGlobalRef,而只调用本机缓冲区地址上的free()。

1 个答案:

答案 0 :(得分:8)

  

当将对JNI方法创建的New[Type]Array,或其他对象的引用返回给Java时,我们是否应该在创建的对象上返回NewGlobalRef调用的结果?

仅当 希望保留该引用以便在将来的JNI调用中使用而不再将其作为JNI方法参数接收时。

  

以后,当Java中不再需要对象时,我们是否需要调用JNI方法对从Java传递的引用执行DeleteGlobalRef

仅当您在其上调用NewGlobalRef()时。

  

或者NewGlobalRef/DeleteGlobalRef只需要在JNI内部,JNI方法调用之间保存对Java对象的引用

绝对正确。

  

如果我们只是将创建的对象返回给Java,我们不需要进行NewGlobalRef/DeleteGlobalRef次调用吗?

再次纠正。

  

我在大型开源项目中看到NewGlobalRef在创建的NewDirectByteBuffer对象(通过malloc()分配的实际缓冲区)上返回结果。后来,当Java中不再需要对象时,会调用JNI方法,而不是DeleteGlobalRef,,而只是在free()获取的本机缓冲区地址上调用GetDirectBufferAddress. }

这将构成DirectByteBuffer对象的泄漏,而不是其本机缓冲区的泄漏。