JNI错误:访问过时的弱全局引用

我在本机代码中缓存对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 M_java_object; public: setJavaObject(jobject obj) { M_java_object = shared_ptr(_JAVA_ENV->NewGlobalRef(obj), g_java_ref_deleter); } shared_ptr 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(&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(&env), JNI_VERSION_1_6 /*version*/); return env; } 

希望可以帮助别人! (请再次原谅我可怜的英语..)