程序什么时候会造成崩溃?
会引发程序运行崩溃基本有两种情况
-
- c++语言层面的错误,比如野指针,除零,内存访问异常等, 这种可以通过信号机制来捕获, 判断信号, 大概知道是什么问题.
-
- 未捕获异常(Uncaught Exception), 可以通过捕获这个异常来做判断.
Uncaught Exception
1.NSException对象
(1) reason:崩溃原因。
(2) callStackSymbols:调用堆栈。
(3) name:崩溃名称
(4) userInfo:崩溃对象。
- 情况一: 通过
try - catch
捕获抛出的异常
@try {
[@"str" substringFromIndex:100];
} @catch (NSException *exception) {
NSLog(@"==>%@==>%@", exception.name, exception.reason);
} @finally {
NSLog(@"finally");
}
这种只能对特定代码做异常捕获, 捕获完之后, exception
不会抛出, 程序继续运行.
- 情况二: 通过
NSSetUncaughtExceptionHandler
设置异常捕获
void uncaughtExceptionHandler(NSException *exception){
NSArray *stackArry= [exception callStackSymbols];
NSString *reason = [exception reason];
NSString *name = [exception name];
NSString *exceptionInfo = [NSString stringWithFormat:@"Exception name:%@\nException reatoin:%@\nException stack :%@",name,reason,stackArry];
}
+ (void)setDefaultHandler {
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
}
当程序运行抛出 exception
时, uncaughtExceptionHandler
会自动捕获异常, 捕获到之后可以自己做处理, 本地分析, 或者上传到服务端收集起来.
这种异常捕获完之后, 因为 exception
本质上来说没有被处理, 程序一样会崩溃.
Signal信号
程序运行报signal, 我遇到的挺少的, 大部分异常都是被Xcode内部处理过的,
如果需要捕获这类异常, 可以这样做
static int s_fatal_signals[] = {
SIGABRT,
SIGBUS,
SIGFPE,
SIGILL,
SIGSEGV,
SIGTRAP,
SIGTERM,
SIGKILL,
};
static int s_fatal_signal_num = sizeof(s_fatal_signals) / sizeof(s_fatal_signals[0]);
+(void)startCrashLog
{
for(int i = 0; i < s_fatal_signal_num; i++) {
signal(s_fatal_signals[i], SignalHandler);
}
}
// 处理捕获的信号值, 每一个信号对应一种错误
void SignalHandler(int signal){
NSLog(@"signal: %d", signal);
// 可以在这里面通过backtrace, 包装堆栈信息和信号值, 再做分析, 我觉得意义不是很大
void* callstack[128];
int frames = backtrace(callstack, 128);
char **strs = backtrace_symbols(callstack, frames);
int I;
NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
for (i = 0;i < 4;i++){
[backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
}
backtrace addObject:[NSString stringWithFormat:@"signal: %d", signal];
free(strs);
NSLog(@"=====>>>>>堆栈<<<<<=====\n%@",backtrace);
}
题外话: backtrace
通过调用callStackSymbols
可以看到当前线程的堆栈信息,
在底层是通过 backtrace
和 backtrace_symbols
函数打印调用栈信息
- backtrace函数用来获取当前线程的调用堆栈, 获取的信息将会被存放在buffer中,它是一个指针数组.
- backtrace_symbols将从backtrace函数获取的信息转化为一个字符串数组,
这里已经自动做了符号化. 而不是单单的内存地址.
参考
iOS崩溃收集
android和iOS平台的崩溃捕获和收集
利用backtrace和backtrace_symbols函数打印调用栈信息