最近遇到一个JNI的问题,一套代码在Android上首次运行是OK的,但是在第二次运行之后设备就会崩溃,查看logcat发现报JNI DETECTED ERROR IN APPLICATION错误。
(1)错误: accessed stale local reference 0x57200019 (index 6 in a table of size 6) JNI DETECTED ERROR IN APPLICATION: jclass is an invalid local reference in call to CallStaticObjectMethod from void com.org.vincent.ccalljava.JNI.getTime() JNI DETECTED ERROR IN APPLICATION: calling static method xxxx with CallxxxxMethodV in call to CallxxxxMethodV综合上面这个错误显示是CallStaticObjectMethod 的jclass 参数非法引用,网上找了一些相关问题的帖子,说明在JNI中有三种不用的引用方式,不同方式有不同的生命周期。结合本地代码,发现最有可能的就是jclass 实例不能用局部引用,必须使用全局引用保持jclass实例在函数退出后还具有生命周期。
改变前:
if(JNI == NULL) { JNI = (*jniEnv)->FindClass(jniEnv,"com/org/vincent/ccalljava/JNI"); if(JNI == NULL){ return -1; } __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "InitProvider Begin 2 ok" ); }改成后:
if(JNI == NULL) { jclass localRef; localRef = (*jniEnv)->FindClass(jniEnv,"com/org/vincent/ccalljava/JNI"); if(JNI == NULL){ return -1; } //创建一个jclass 的全局引用 JNI=(*jniEnv)->NewGlobalRef(jniEnv,localRef); __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "InitProvider Begin 2 ok" ); }JNI是在jni中定义的全局变量,如果这个函数一旦执行完退出,那么JNI指向的jclass类型内存可能会被GC回收,那么JNI就指向非法地址。 事后验证判定是对的 参考:blog
