signal 11 (SIGSEGV)错误排查

jni调试最蛋疼的就是signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4这种错误,爆出来完全不知道是哪句代码造成的,很难定位到问题所在,网上很多人说是内存原因,还有说是空指针,不一而论。
我的错误是这样的:

02-16 14:54:53.041 20897-20897/? I/AEE/AED: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4
02-16 14:54:53.058 20897-20897/? I/AEE/AED:     r0 00000001  r1 00000002  r2 00000000  r3 0000002f
02-16 14:54:53.058 20897-20897/? I/AEE/AED:     r4 00000000  r5 f4489000  r6 f4400000  r7 f6fb3c0c
02-16 14:54:53.058 20897-20897/? I/AEE/AED:     r8 f48000c0  r9 f6fb3c0c  sl 00000001  fp 00000002
02-16 14:54:53.058 20897-20897/? I/AEE/AED:     ip f6fb3c24  sp dc144060  lr 00000000  pc f6f7f566  cpsr 600f0030
02-16 14:54:53.059 20897-20897/? I/AEE/AED: backtrace:
02-16 14:54:53.059 20897-20897/? I/AEE/AED:     #00 pc 00042566  /system/lib/libc.so (je_arena_dalloc_bin_locked+365)
02-16 14:54:53.059 20897-20897/? I/AEE/AED:     #01 pc 0004fa0b  /system/lib/libc.so (je_tcache_bin_flush_small+234)
02-16 14:54:53.059 20897-20897/? I/AEE/AED:     #02 pc 0004a33f  /system/lib/libc.so (ifree+446)
02-16 14:54:53.059 20897-20897/? I/AEE/AED:     #03 pc 00035775  /data/app/我的包名-1/lib/arm/libjni-lib.so (std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >::~basic_string()+148)
02-16 14:54:53.059 20897-20897/? I/AEE/AED:     #04 pc 00086087  /data/app/我的包名-1/lib/arm/libjni-lib.so (WPZHandler::OnRspQryPosition(TradingLibFast::RspQryPositionResponse*)+2518)
02-16 14:54:53.059 20897-20897/? I/AEE/AED:     #05 pc 0004451d  /data/app/我的包名-1/lib/arm/libjni-lib.so (TradingLibFast::TLClient::HandleMessage(TradingLibFast::Message&)+964)
02-16 14:54:53.059 20897-20897/? I/AEE/AED:     #06 pc 00041083  /data/app/我的包名-1/lib/arm/libjni-lib.so (TradingLibFast::TLClient::RecvFun()+226)
02-16 14:54:53.059 20897-20897/? I/AEE/AED:     #07 pc 00066cfb  /data/app/我的包名-1/lib/arm/libjni-lib.so (fastdelegate::FastDelegate0<bool>::operator()() const+94)
02-16 14:54:53.059 20897-20897/? I/AEE/AED:     #08 pc 00066889  /data/app/我的包名-1/lib/arm/libjni-lib.so (TradingLibFast::TLThread::ProcessInThread()+68)
02-16 14:54:53.059 20897-20897/? I/AEE/AED:     #09 pc 00066837  /data/app/我的包名-1/lib/arm/libjni-lib.so (TradingLibFast::ThreadFunc(void*)+26)
02-16 14:54:53.059 20897-20897/? I/AEE/AED:     #10 pc 00017003  /system/lib/libc.so (__pthread_start(void*)+30)
02-16 14:54:53.059 20897-20897/? I/AEE/AED:     #11 pc 0001506f  /system/lib/libc.so (__start_thread+6)

然后就是nativeCrashListener,这个log其实已经很清晰了,记得一定不要过滤,选择no Filters,日志级别选择Verbose最低级别,这样才能看到最全的log信息。je_arena_dalloc_bin_locked显示就是内存处理出问题了,jni代码出问题导致了系统错误。再往下包含“我的包名”的log信息就显示了错误的具体位置,越上面就是越具体的位置,越下面范围就越广,这里大致就定位了问题代码大概在哪几行。不过这几行我纠结了许久,因为觉得没有问题,闪退只是偶现,后来看到另外一篇文章:常见 core dump 原因分析signal 11 - SIGSEGV,说signal 11 (SIGSEGV)是由于内存释放不当(多次释放或者空释放)或者空指针引起的,遂检查,终于发现了问题:
在调用NewStringUTF方法的时候使用了ReleaseStringUTFChars进行释放,这个释放内存的方法并不能在此处使用,应该使用DeleteLocalRef来释放引用即可。
jni具体内存释放对应方法如下:
总体原则:释放所有对object的引用

1.FindClass
例如,

jclass ref= (env)->FindClass("java/lang/String"); 
env->DeleteLocalRef(ref); 

2.NewString/ NewStringUTF/NewObject/NewByteArray
例如,

jstring     (*NewString)(JNIEnv*, const jchar*, jsize);    
const jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*);     void        (*ReleaseStringChars)(JNIEnv*, jstring, const jchar*); 
jstring     (*NewStringUTF)(JNIEnv*, const char*);    
const char* (*GetStringUTFChars)(JNIEnv*, jstring, jboolean*);     void        (*ReleaseStringUTFChars)(JNIEnv*, jstring, const char*); 
env->DeleteLocalRef(ref); 

3.GetObjectField/GetObjectClass/GetObjectArrayElement

jclass ref = env->GetObjectClass(robj); 
env->DeleteLocalRef(ref);  

4.GetByteArrayElements和GetStringUTFChars

jbyte* array= (*env)->GetByteArrayElements(env,jarray,&isCopy); 
(*env)->ReleaseByteArrayElements(env,jarray,array,0); 
const char* input =(*env)->GetStringUTFChars(env,jinput, &isCopy); 
(*env)->ReleaseStringUTFChars(env,jinput,input); 

5.NewGlobalRef/DeleteGlobalRef
jobject (NewGlobalRef)(JNIEnv, jobject);
void (DeleteGlobalRef)(JNIEnv, jobject);
例如,

jobject ref= env->NewGlobalRef(customObj); 
env->DeleteGlobalRef(customObj); 

改完果然就没有再闪退了!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 什么是JNI? JNI 是java本地开发接口.JNI 是一个协议,这个协议用来沟通java代码和外部的本地代码(...
    a_tomcat阅读 2,854评论 0 54
  • JNI编程 JNI是一种本地编程接口。它允许运行在JAVA虚拟机中的JAVA代码和用其他编程语言,诸如C语言、C+...
    微尘_8957阅读 470评论 0 0
  • 0.要素1.类操作2.异常操作3.全局及局部引用4.对象操作5.字符串操作6.数组操作7.访问对象的属性和方法7....
    MagicalGuy阅读 1,387评论 0 2
  • 原链接:http://www.ibm.com/developerworks/cn/java/j-jni/ 使用 J...
    王朋6阅读 7,971评论 0 8
  • 前言 JNI 的全称是:Java Native Interface,即连接 Java 虚拟机和本地代码的接口,它允...
    全站工程师阅读 3,921评论 0 5