JNI DETECTED ERROR IN APPLICATION解决记录
2015-08-13 14:23
591 查看
最近遇到一个JNI的问题,同一套代码在Android4.4版本前的设备上运行是OK的,但是在Android5.0之后的设备上就会崩溃,查看logcat发现报JNI DETECTED ERROR IN APPLICATION错误。
(1)第一个错误:
JNI DETECTED ERROR IN APPLICATION: calling static method xxxx with CallxxxxMethodV in call to CallxxxxMethodV
有过JNI编程经验的就会知道,调用方法分static和非static两种,分别会用到
GetStaticMethodID GetMethodID
CallStatic<type>Method Call<type>Method
其中<type>指Int, Long, Char等类型
问题的原因就是编写JNI代码的同事混用了这两种方式,先用了GetStaticMethodID,然后又用的非static的CallIntMethod方法,Android4.4之前版本JNI检查机制没有Android5.0之后的版本严格,所以没有报错,程序也不会崩溃,但正确的方式应该是GetMethodID+Call<type>Method,GetStaticMethodID+CallStatic<type>Method,这个问题解决后又接着又报出了下面的错误。
(2)第二个错误:
JNI DETECTED ERROR
IN APPLICATION: native code passing in reference to invalid stack indirect reference table or invalid reference: 0xfff5f1b0
in call to CallVoidMethod <==这一行报错是问题的切入点
这个错误显示是CallVoidMethod的参数非法引用,网上找了一些相关问题的帖子,结合本地代码,发现最有可能的就是线程间不能直接传递JNIEnv和jobject这类线程专属属性值导致,要知道JavaVM是属于java进程的,每个进程只有一个JavaVM,而这个JavaVM可以被多线程共享,但是JNIEnv和jobject是属于线程私有的,不能共享,那有什么办法解决呢?这里我们不讲JNIEnv的线程间传递,有兴趣的网上可以找到相关帖子,而jobject可以用全局引用的方式在多线程间使用,举个简单的例子:
(1)第一个错误:
JNI DETECTED ERROR IN APPLICATION: calling static method xxxx with CallxxxxMethodV in call to CallxxxxMethodV
有过JNI编程经验的就会知道,调用方法分static和非static两种,分别会用到
GetStaticMethodID GetMethodID
CallStatic<type>Method Call<type>Method
其中<type>指Int, Long, Char等类型
问题的原因就是编写JNI代码的同事混用了这两种方式,先用了GetStaticMethodID,然后又用的非static的CallIntMethod方法,Android4.4之前版本JNI检查机制没有Android5.0之后的版本严格,所以没有报错,程序也不会崩溃,但正确的方式应该是GetMethodID+Call<type>Method,GetStaticMethodID+CallStatic<type>Method,这个问题解决后又接着又报出了下面的错误。
(2)第二个错误:
JNI DETECTED ERROR
IN APPLICATION: native code passing in reference to invalid stack indirect reference table or invalid reference: 0xfff5f1b0
in call to CallVoidMethod <==这一行报错是问题的切入点
这个错误显示是CallVoidMethod的参数非法引用,网上找了一些相关问题的帖子,结合本地代码,发现最有可能的就是线程间不能直接传递JNIEnv和jobject这类线程专属属性值导致,要知道JavaVM是属于java进程的,每个进程只有一个JavaVM,而这个JavaVM可以被多线程共享,但是JNIEnv和jobject是属于线程私有的,不能共享,那有什么办法解决呢?这里我们不讲JNIEnv的线程间传递,有兴趣的网上可以找到相关帖子,而jobject可以用全局引用的方式在多线程间使用,举个简单的例子:
#Include <jni.h> #include <pthread.h> pthread_t pthread; jobject object; JavaVM* jvm; void *run(void *arg) { JNIEnv * jenv; jvm->AttachCurrentThread(&jenv, NULL); jenv->CallVoidMethod(object, jnv->GetMethodID(jnv->GetObjectClass(object), "foo", "()V")); jenv->DeleteGlobalRef(object); jvm->DetachCurrentThread(); return NULL; } void Java_com_program_Initialize(JNIEnv*jenv, jobject caller) { /*要想在新线程中使用对象caller,就必须以全局引用方式保存,否则caller只是局部引用,本方法返回后就会销毁*/ object = jnv->NewGlobalRef(caller); jenv->GetJavaVM(&jvm); pthread_create(&thread, NULL, run, NULL); }再回到前面的问题,按照这个线索,我在本地JNI代码里发现在pthread_create创建新线程之前,仅仅将jobject保存在了一个全局变量里面,而没有使用全局引用,以上面的代码为例,即本地JNI代码里进行了类似object = caller;的赋值,这显然是没有用的,一旦函数返回,caller就会被GC回收销毁,object指向的就是一个非法地址,最终导致上面的JNI错误。
相关文章推荐
- iOS第三方支付-支付宝支付
- pushViewController and presentViewController are not working.
- Hibernate报错 ** is not mapping
- Cocos2d-x与ios内存管理分析(在游戏中减少内存压力)
- 4000 获取键盘的高度变化
- Object.observe()带来的数据绑定变革
- 火云开发课堂 - 《使用Cocos2d-x 开发3D游戏》系列 第一节:3D时代来临!
- android--解--它们的定义tabhost(动态添加的选项+用自己的主动性横向滑动标签+手势切换标签页和内容特征)
- IOS 将毫秒数转换为年月日时分秒的时间
- Android布局问题基本理解
- android: 横竖屏切换总结-布局改变和数据保存
- android短信验证码功能实现,包含按钮倒计时操作
- Ionic开发时,默认样式android和ios的一些不同
- android webview 选择文件(拍照,本地相册) 百度定位自适应屏幕
- 安卓设置自定义字体的解决方案
- Android service的全面总结
- 《我们立志要做出一款颠覆程序员工作方式的APP,你想来试试吗?》
- Android Context 是什么?
- Android初体验
- Android Studio Tips -- 布局预览