2015-04-27 224 views
1

將對JNI方法中創建的對象的引用返回給Java時,是否應該在創建的對象上返回NewGlobalRef調用的結果?而且,分別在稍後,當Java中不再需要對象時,我們是否需要調用JNI方法對從Java傳入的引用執行DeleteGlobalRef?當返回在JNI中創建的對象時,NewGlobalRef/DeleteGlobalRef

或者NewGlobalRef/DeleteGlobalRef只需要在JNI內部保存對Java對象的引用,在JNI方法調用之間,並且如果我們簡單地將創建的對象返回給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中更需要的,有一個叫到不調用DeleteGlobalRef的JNI方法,而只是在本機緩衝區地址上調用free()。

+0

http://developer.android.com/training/articles/perf-jni.html – fadden

回答

6

當返回參考New[Type]Array,或JNI方法創建Java之外的對象,我們應該回到NewGlobalRef調用創建對象的結果呢?

只有當你想保留在未來的JNI使用該引用調用,而無需再次接受它作爲一個JNI方法的參數。

分別後來,當對象不再需要在Java中的時候,我們是否需要調用JNI方法對從Java傳入的引用執行DeleteGlobalRef

只有當你叫它NewGlobalRef()就可以了。

或者只持有內部JNI爲Java對象引用需要NewGlobalRef/DeleteGlobalRef,JNI方法調用之間

完全正確的。

如果我們只是返回創建的對象到Java我們不需要做NewGlobalRef/DeleteGlobalRef調用?

再次校正。

我看到創建NewDirectByteBuffer對象(真正的緩衝區通過malloc()分配),返回NewGlobalRef導致大量的開源項目。後來,當對象沒有更多的在Java中要求,還有就是JNI方法的調用,即不做DeleteGlobalRef,只是調用free()GetDirectBufferAddress.

獲得本地緩衝區地址將構成的泄漏DirectByteBuffer對象,但不是其本機緩衝區。

+0

謝謝! 我假設,爲了解決示例代碼中的問題,在free()調用之前添加DeleteGlobalRef對象傳遞給我們的對象引用是不正確的,因爲該引用可能在Java代碼執行期間被修改並且是完全不同的來自NewGlobalRef返回的引用。 它需要:移除對NewGlobalRef的調用,或將JNI存儲在全局引用中,並且在調用free()之前,對存儲在JNI中的ref執行DeleteGlobalRef,而不是傳遞給釋放函數的對象參數ref。 – Dima

+0

我剛剛回答了這個問題。 – EJP

+0

是的,我理解實際的決定,但只是想澄清一下關於JNI機制,要明白DeleteGlobalRef對象的ref從Java傳遞過來完全不正確,即使我們返回到NewGlobalRef的Java結果。我很抱歉做冗長的事,這是我對英語的薄弱知識。 – Dima