2017-03-23 80 views
3

我通過調用返回一個jobject值的本地代碼來創建一個Java對象。JNI可以釋放Java層對象嗎?

Java代碼:

Object myObj = nativeCreateObject(); 

本地代碼:

jobject* hold_ref; 
JNIEXPORT jobject JNICALL 
nativeCreateObject(JNIEnv *env ...) { 
    ..... 
    result = env->NewGlobalRef(jobj); 
    hold_ref = &result; 
    return result; 
} 

我的問題是:我是否可以使用hold_ref後來在本地層參考釋放MyObj中? 例如 本地代碼:

*hold_ref = NULL; 

然後MyObj中使用Java層爲空? 如果不是,我怎麼能通過本地代碼釋放這個對象?

+1

不需要。您需要閱讀[JNI規範的第4章](https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#global_and_local_references)。 – EJP

+0

@EJP感謝您的信息。閱讀後...我仍然沒有找到答案。你能幫我簡單地給我一些關於這個問題的建議嗎?提前致謝! – ignorer

+1

'result'和'myObj'是對同一個對象的兩個不同的引用。只要至少有一個引用存在,該對象就不能被垃圾回收。 _Maybe_你可以將'nativeCreateObject'的結果包裝在Java的'WeakReference'中(這不是我曾經試過的,所以我沒有做任何保證)。順便說一句,'* hold_ref = NULL;'不是你如何刪除一個全局引用。 – Michael

回答

2

我不知道,你要實現,但這裏是什麼它是如何工作的basicly:

我是否可以使用hold_ref後來在本地層參考釋放MyObj中?

是的,你可以和應該使用env->DeleteGlobalRef(myObj)來釋放您所創建的全球參考,因此垃圾收集器清理和finaly銷燬對象。

然後Java層中的myObj爲null?如果不是,我如何通過本機代碼釋放此對象?

當您從jni本機代碼中刪除引用時,您的Java變量將無法變爲空。 Java本身擁有一個引用來防止垃圾回收對象被刪除。

您可能需要使用這種方式:

C++

jobject* hold_ref; 

JNIEXPORT jobject JNICALL nativeCreateObject(JNIEnv *env ...) { 
    ..... 
    result = env->NewGlobalRef(jobj); 
    hold_ref = &result; 
    return result; 
} 

JNIEXPORT void JNICALL nativeDestroyObject(JNIEnv *env ...) { 
    ..... 
    env->DeleteGlobalRef(jobj); 
    hold_ref = nullptr; 
} 

JAVA

// Creates two references (native and local variable) 
Object myObj = nativeCreateObject(); 

// Deletes the native reference, but not the local one 
nativeDeleteObject(myObj); 
// myObj != null 

myObj = null; 
// now there is no reference to your created object 
// the garbage collector may destroy it any time 

如果你想以某種方式無效的對象,我建議來管理國家和拋一個例外,如果對象是這樣失效的:

class MyInvalidateableObject { 

    private boolean invalidated = false; 

    public void invalidate() { 
     this.invalidated = true; 
    } 

    public void foo() { 
     if (invalidated) 
      throw new IllegalStateException("Object has been invalidated"); 
     ... // do the normal stuff 
    } 
} 

只需從本機代碼調用invalidate()即可防止它再次被使用。