我在本机代码中缓存了对 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
并错误地使用它。由此blog http://android-developers.blogspot.com/2011/11/jni-local-reference-changes-in-ics.html我发现 :
尽管任何给定的 JNIEnv* 只能在一个线程上使用,但由于 Android 在 JNIEnv* 中从未有任何每线程状态,因此过去可以在错误的线程上使用 JNIEnv*。现在有一个每线程本地引用表,仅在正确的线程上使用 JNIEnv* 至关重要。
所以我认为我缓存没有问题JNIEnv
并在一个线程中使用它,但实际上JNIEnv
当程序进入java环境并返回到本机环境时就已经过时了。 (呃...原谅我糟糕的英语)
并从文档 http://developer.android.com/training/articles/perf-jni.html, 我发现 :
如果一段代码没有其他方法来获取其 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;
}
希望可以帮助别人! (请再次原谅我糟糕的英语..)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)