簡體   English   中英

JNI錯誤:訪問過時的弱全局引用

[英]JNI Error: accessed stale weak global reference

我在本機代碼中緩存對Java對象的引用,如下所示:

// java global reference deleter
// _JAVA_ENV  is an instance of JNIEnv that is cached globally and just
// valid in current thread scope
static void g_java_ref_deleter(jobject ptr) {
   _JAVA_ENV->DeleteGlobalRef(ptr);
}

// native class caches a java object reference
class NativeA {
private:
    shared_ptr<_jobject> M_java_object;
public:
    setJavaObject(jobject obj) {
        M_java_object = shared_ptr<_jobject>(_JAVA_ENV->NewGlobalRef(obj), g_java_ref_deleter);
    }

    shared_ptr<_jobject> getJavaObject() const {
        return M_java_object;
    }
}

我在另一個本地類中訪問它:

class NativeB {
public:
    void doSomething(NativeA& a) {
        // here I got an error: accessed stale weak global reference
        // make_record do something on java object (set float field actually)
        make_record(a.getJavaObject().get());
    }
}

此代碼運行在Android 4.3上。 為什么我會收到此錯誤以及如何解決?

好的,我已經解決了這個問題! 實際上我緩存了_JAVA_ENV並錯誤地使用它。 從這個博客我發現:

雖然任何給定的JNIEnv *僅在一個線程上有效,但因為Android在JNIEnv *中從未有任何每線程狀態,所以過去可能會在錯誤的線程上使用JNIEnv *。 現在有一個每線程的本地參考表,至關重要的是你只在正確的線程上使用JNIEnv *。

所以我認為沒有問題,我緩存JNIEnv並在一個線程中使用它,但實際上當程序進入java環境並返回到本機環境時, JNIEnv是陳舊的。 (呃...原諒我可憐的英語)

文檔中 ,我發現:

如果一段代碼沒有其他方法來獲取它的JNIEnv,你應該共享JavaVM,並使用GetEnv來發現線程的JNIEnv。

所以,你應該緩存JavaVM,並使用它來獲取JNIEnv ,代碼如下:

JavaVM* g_jvm;

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    g_jvm = vm;
    JNIEnv* env;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }

    // Get jclass with env->FindClass.
    // Register methods with env->RegisterNatives.

    return JNI_VERSION_1_6;
}

JNIEnv* getJNIEnv() {
    JNIEnv* env;
    g_jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6 /*version*/);
    return env;
}

希望可以幫助別人! (請再次原諒我可憐的英語..)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM