[英]JNI Error: accessed stale weak global reference
I cache a reference to a Java object in my native code, just like this: 我在本机代码中缓存对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;
}
}
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());
}
}
This code run onto Android 4.3. 此代码运行在Android 4.3上。 Why do I get this error and how can I fix it?
为什么我会收到此错误以及如何解决?
OK, I've solved this problem! 好的,我已经解决了这个问题! Actually I cached
_JAVA_ENV
and use it mistakenly. 实际上我缓存了
_JAVA_ENV
并错误地使用它。 From this blog I found : 从这个博客我发现:
Although any given JNIEnv* is only valid for use on one thread, because Android never had any per-thread state in a JNIEnv*, it used to be possible to get away with using a JNIEnv* on the wrong thread.
虽然任何给定的JNIEnv *仅在一个线程上有效,但因为Android在JNIEnv *中从未有任何每线程状态,所以过去可能会在错误的线程上使用JNIEnv *。 Now there's a per-thread local reference table, it's vital that you only use a JNIEnv* on the right thread.
现在有一个每线程的本地参考表,至关重要的是你只在正确的线程上使用JNIEnv *。
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. 所以我认为没有问题,我缓存
JNIEnv
并在一个线程中使用它,但实际上当程序进入java环境并返回到本机环境时, JNIEnv
是陈旧的。 (eh... forgive my poor English) (呃...原谅我可怜的英语)
And from the documentation , I found : 从文档中 ,我发现:
If a piece of code has no other way to get its JNIEnv, you should share the JavaVM, and use GetEnv to discover the thread's JNIEnv.
如果一段代码没有其他方法来获取它的JNIEnv,你应该共享JavaVM,并使用GetEnv来发现线程的JNIEnv。
So, you should cache the JavaVM, and use it to get JNIEnv
, the code would be like this : 所以,你应该缓存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;
}
Hope can help someone! 希望可以帮助别人! (please forgive my poor English again..)
(请再次原谅我可怜的英语..)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.