问题描述
我在本地code缓存到Java对象的引用,就像这样:
I cache a reference to a Java object in my native code, just like this:
// 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;
}
}
和访问它在另一本机类:
and I access it in another native class:
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());
}
}
这code运行到Android 4.3的。为什么我得到这个错误,我该如何解决这个问题?
This code run onto Android 4.3. Why do I get this error and how can I fix it?
推荐答案
OK,我已经解决了这个问题!其实我缓存 _JAVA_ENV
,并错误地使用它。从这个我发现
OK, I've solved this problem! Actually I cached _JAVA_ENV
and use it mistakenly. From this blog I found :
尽管任何给定的JNIEnv *只适用于在一个线程中使用,由于Android从来没有在JNIEnv的*有过任何每个线程的状态,它曾经是可能逃脱错误的线程上使用的JNIEnv *。现在有一个每线程本地参照表,这是至关重要的,你只有正确的线程上使用的JNIEnv *。
所以我想有我缓存的JNIEnv
并在一个线程中使用没有问题,但实际上的JNIEnv
是陈旧的,当程序进入java环境,回到本地环境。 (呃...原谅我的英语很差)
So I thought there is no problem that I cache the JNIEnv
and use it in one thread, but actually the JNIEnv
was stale when the program get into java environment and returned to native environment. (eh... forgive my poor English)
和来自,我发现:
如果一张code有没有其他的方式来获得它的JNIEnv,你应该分享的JavaVM,并用getenv发现线程的JNIEnv的。
所以,你应该缓存JavaVM的,并用它来获得的JNIEnv
中,code会是这样的:
So, you should cache the JavaVM, and use it to get JNIEnv
, the code would be like this :
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;
}
希望可以帮助别人! (请原谅一次我可怜的英语。)
Hope can help someone! (please forgive my poor English again..)
这篇关于JNI错误:访问陈旧弱全局引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!