关于异常捕获那些事
2013-07-29 10:26
267 查看
iOS提供的异常捕获功能比较简单,它能捕获到一些数据越界,发送方法的错误,但是捕获不到内存级别的错误,网上搜了一个类,捕获这个内存级别的问题,包括友盟都是这么干得,
一篇老外的文章也是介绍异常捕获的情况:http://www.mikeash.com/pyblog/friday-qa-2011-04-01-signal-handling.html
还有C和指针上也有一段关于异常的介绍:Page:338 关于信号的介绍
根据它的说法,当一些异常的信号发生的时候,程序会做出缺省的反应,没有什么标准的缺省的反应,但大部分的编译器都选择了终止应用程序,也就是我们说的程序crash了。我们可以去设置一些信号处理函数,当异常信号发生的时候,我们指定它们帮我们处理一些事情。
据C和指针描述信号处理函数能做的事情非常少: 除了能向一个静态变量赋值外,无法访问其他任何静态数据。
.h文件
#import <Foundation/Foundation.h>
@interface UncaughtExceptionHandler : NSObject
{
BOOL dismissed;
}
void InstallUncaughtExceptionHandler();
@end
.m文件
#import "UncaughtExceptionHandler.h"
#include <libkern/OSAtomic.h>
#include <execinfo.h>
NSString *const UncaughtExceptionHandlerSignalExceptionName =@"UncaughtExceptionHandlerSignalExceptionName";
NSString *const UncaughtExceptionHandlerSignalKey =
@"UncaughtExceptionHandlerSignalKey";
NSString *const UncaughtExceptionHandlerAddressesKey =
@"UncaughtExceptionHandlerAddressesKey";
volatile int32_t UncaughtExceptionCount = 0;
const int32_t UncaughtExceptionMaximum = 10;
const NSInteger UncaughtExceptionHandlerSkipAddressCount = 0;
const NSInteger UncaughtExceptionHandlerReportAddressCount = 10;
@implementation UncaughtExceptionHandler
void InstallUncaughtExceptionHandler()
{
signal(SIGABRT, MySignalHandler);
signal(SIGILL, MySignalHandler);
signal(SIGSEGV, MySignalHandler);
signal(SIGFPE, MySignalHandler);
signal(SIGBUS, MySignalHandler);
signal(SIGPIPE, MySignalHandler);
}
+ (NSArray *)backtrace
{
void* callstack[128];
int frames = backtrace(callstack, 128);
char **strs = backtrace_symbols(callstack, frames);
int i;
NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
for (
i = UncaughtExceptionHandlerSkipAddressCount;
i < UncaughtExceptionHandlerSkipAddressCount +
UncaughtExceptionHandlerReportAddressCount;
i++)
{
[backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
}
free(strs);
return backtrace;
}
- (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex
{
if (anIndex == 0)
{
dismissed =YES;
}
}
- (void)handleException:(NSException *)exception
{
NSLog(@"%@",[[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]);
UIAlertView *alert =
[[[UIAlertView alloc]
initWithTitle:NSLocalizedString(@"Unhandled exception",nil)
message:[NSString stringWithFormat:NSLocalizedString(
@"You can try to continue but the application may be unstable.\n"
@"%@\n%@",
nil),
[exception reason],
[[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]]
delegate:self
cancelButtonTitle:NSLocalizedString(@"Quit",nil)
otherButtonTitles:NSLocalizedString(@"Continue",nil),
nil]
autorelease];
[alert show];
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
while (!dismissed)
{
for (NSString *modein (NSArray *)allModes)
{
CFRunLoopRunInMode((CFStringRef)mode, 0.001,false);
}
}
CFRelease(allModes);
NSSetUncaughtExceptionHandler(NULL);
signal(SIGABRT, SIG_DFL);
signal(SIGILL, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
signal(SIGFPE, SIG_DFL);
signal(SIGBUS, SIG_DFL);
signal(SIGPIPE, SIG_DFL);
if ([[exception name] isEqual:UncaughtExceptionHandlerSignalExceptionName])
{
kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]);
}
else
{
[exception raise];
}
}
void MySignalHandler(int signal)
{
int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
if (exceptionCount > UncaughtExceptionMaximum)
{
return;
}
NSMutableDictionary *userInfo =
[NSMutableDictionary dictionaryWithObject:[NSNumber numberWithInt:signal] forKey:UncaughtExceptionHandlerSignalKey];
NSArray *callStack = [UncaughtExceptionHandler backtrace];
[userInfo setObject:callStack forKey:UncaughtExceptionHandlerAddressesKey];
[[[[UncaughtExceptionHandler alloc] init] autorelease]
performSelectorOnMainThread:@selector(handleException:)
withObject: [NSException exceptionWithName:UncaughtExceptionHandlerSignalExceptionName
reason: [NSString stringWithFormat:NSLocalizedString(@"Signal %d was raised.\n"@"%@%@",nil),signal,
getAppInfo(),callStack]
userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:signal]
forKey:UncaughtExceptionHandlerSignalKey]]waitUntilDone:YES];
}
NSString* getAppInfo()
{
NSString *appInfo = [NSString stringWithFormat:@"App :%@ %@ %@(%@)\nDevice : %@\nOS Version : %@ %@\nUDID :\n",
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"],
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"],
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"],
[UIDevice currentDevice].model,
[UIDevice currentDevice].systemName,
[UIDevice currentDevice].systemVersion,
[UIDevice currentDevice].uniqueIdentifier];
NSLog(@"Crash!!!! %@", appInfo);
return appInfo;
}
@end
可以看到是利用了unix底层的一些性能去做了一些处理.
一篇老外的文章也是介绍异常捕获的情况:http://www.mikeash.com/pyblog/friday-qa-2011-04-01-signal-handling.html
还有C和指针上也有一段关于异常的介绍:Page:338 关于信号的介绍
根据它的说法,当一些异常的信号发生的时候,程序会做出缺省的反应,没有什么标准的缺省的反应,但大部分的编译器都选择了终止应用程序,也就是我们说的程序crash了。我们可以去设置一些信号处理函数,当异常信号发生的时候,我们指定它们帮我们处理一些事情。
据C和指针描述信号处理函数能做的事情非常少: 除了能向一个静态变量赋值外,无法访问其他任何静态数据。
.h文件
#import <Foundation/Foundation.h>
@interface UncaughtExceptionHandler : NSObject
{
BOOL dismissed;
}
void InstallUncaughtExceptionHandler();
@end
.m文件
#import "UncaughtExceptionHandler.h"
#include <libkern/OSAtomic.h>
#include <execinfo.h>
NSString *const UncaughtExceptionHandlerSignalExceptionName =@"UncaughtExceptionHandlerSignalExceptionName";
NSString *const UncaughtExceptionHandlerSignalKey =
@"UncaughtExceptionHandlerSignalKey";
NSString *const UncaughtExceptionHandlerAddressesKey =
@"UncaughtExceptionHandlerAddressesKey";
volatile int32_t UncaughtExceptionCount = 0;
const int32_t UncaughtExceptionMaximum = 10;
const NSInteger UncaughtExceptionHandlerSkipAddressCount = 0;
const NSInteger UncaughtExceptionHandlerReportAddressCount = 10;
@implementation UncaughtExceptionHandler
void InstallUncaughtExceptionHandler()
{
signal(SIGABRT, MySignalHandler);
signal(SIGILL, MySignalHandler);
signal(SIGSEGV, MySignalHandler);
signal(SIGFPE, MySignalHandler);
signal(SIGBUS, MySignalHandler);
signal(SIGPIPE, MySignalHandler);
}
+ (NSArray *)backtrace
{
void* callstack[128];
int frames = backtrace(callstack, 128);
char **strs = backtrace_symbols(callstack, frames);
int i;
NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
for (
i = UncaughtExceptionHandlerSkipAddressCount;
i < UncaughtExceptionHandlerSkipAddressCount +
UncaughtExceptionHandlerReportAddressCount;
i++)
{
[backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
}
free(strs);
return backtrace;
}
- (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex
{
if (anIndex == 0)
{
dismissed =YES;
}
}
- (void)handleException:(NSException *)exception
{
NSLog(@"%@",[[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]);
UIAlertView *alert =
[[[UIAlertView alloc]
initWithTitle:NSLocalizedString(@"Unhandled exception",nil)
message:[NSString stringWithFormat:NSLocalizedString(
@"You can try to continue but the application may be unstable.\n"
@"%@\n%@",
nil),
[exception reason],
[[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey]]
delegate:self
cancelButtonTitle:NSLocalizedString(@"Quit",nil)
otherButtonTitles:NSLocalizedString(@"Continue",nil),
nil]
autorelease];
[alert show];
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
while (!dismissed)
{
for (NSString *modein (NSArray *)allModes)
{
CFRunLoopRunInMode((CFStringRef)mode, 0.001,false);
}
}
CFRelease(allModes);
NSSetUncaughtExceptionHandler(NULL);
signal(SIGABRT, SIG_DFL);
signal(SIGILL, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
signal(SIGFPE, SIG_DFL);
signal(SIGBUS, SIG_DFL);
signal(SIGPIPE, SIG_DFL);
if ([[exception name] isEqual:UncaughtExceptionHandlerSignalExceptionName])
{
kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]);
}
else
{
[exception raise];
}
}
void MySignalHandler(int signal)
{
int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
if (exceptionCount > UncaughtExceptionMaximum)
{
return;
}
NSMutableDictionary *userInfo =
[NSMutableDictionary dictionaryWithObject:[NSNumber numberWithInt:signal] forKey:UncaughtExceptionHandlerSignalKey];
NSArray *callStack = [UncaughtExceptionHandler backtrace];
[userInfo setObject:callStack forKey:UncaughtExceptionHandlerAddressesKey];
[[[[UncaughtExceptionHandler alloc] init] autorelease]
performSelectorOnMainThread:@selector(handleException:)
withObject: [NSException exceptionWithName:UncaughtExceptionHandlerSignalExceptionName
reason: [NSString stringWithFormat:NSLocalizedString(@"Signal %d was raised.\n"@"%@%@",nil),signal,
getAppInfo(),callStack]
userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:signal]
forKey:UncaughtExceptionHandlerSignalKey]]waitUntilDone:YES];
}
NSString* getAppInfo()
{
NSString *appInfo = [NSString stringWithFormat:@"App :%@ %@ %@(%@)\nDevice : %@\nOS Version : %@ %@\nUDID :\n",
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"],
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"],
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"],
[UIDevice currentDevice].model,
[UIDevice currentDevice].systemName,
[UIDevice currentDevice].systemVersion,
[UIDevice currentDevice].uniqueIdentifier];
NSLog(@"Crash!!!! %@", appInfo);
return appInfo;
}
@end
可以看到是利用了unix底层的一些性能去做了一些处理.
相关文章推荐
- 关于async & await(TAP)异步模型的异常捕获
- 关于正则匹配的异常捕获
- 关于运行时异常RuntimeException捕获的小测试
- 关于未捕获异常的处理(WPF)
- 关于Android中多线程中异常捕获出现的问题和解决办法
- SEH-关于捕获memcpy的异常
- 【java解惑】关于异常捕获的三条要求
- 关于SQLServer2005的学习笔记——异常捕获及处理
- 关于未捕获异常的处理(WPF)
- 关于python3捕获cx_oracle抛出的异常错误
- 关于异常的抛出,捕获和拦截的新理解
- 关于ANR异常捕获与分析,你所需要知道的一切
- Android关于全局异常捕获及发送到服务器
- 关于存储过程和函数异常出现和JAVA捕获简单处理方案
- 关于未捕获异常的处理(WPF)
- 关于抛出异常和捕获异常
- 【java解惑】关于异常捕获的三条要求
- 关于构造中new的异常捕获!
- 关于异常捕获 try catch的说明
- 无法捕获异常:Java关于在catch中抛出一个异常给外围函数却捕获不到该异常的思考