YGben

让我头疼的Crash到底在哪里?(一)


程序猿和BUG就是相爱相杀,而Crash就是终极BUG。自己不把Crash解决,自己就会Crash。

遇到Crash

每次看到如下这些令人恐惧的东西,我都心中一颤,告诉自己:平常心。

1
2
3
4
Exception Type: EXC_CRASH (SIGKILL)
Exception Type: EXC_BAD_ACCESS (SIGABRT)
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Type: 00000020

Exception Type表示异常类型,通常在崩溃日志很常见。

追根溯源,类似 SIGABRT SIGSEGV 的宏定义,定义在sys/signal.h中,表示发送给程序的不同信号。不管怎么说,就是崩了。

当我得知这些涉及到LINUX命令的理解时,我想我又差了一大截。参考我了解

SIGSEGV 非法内存访问
SIGABRT 异常终止,absort()引起
SIGKILL 程序被杀死

之后,我才意识到在iOS中有一个类 NSException 异常处理的类。原来诸如:

reason: ‘-[ViewController click]: unrecognized selector sent to instance 0x7fe88d4691e0’

Xcode给我们报的错,就是因为NSException中的NSSetUncaughtExceptionHandler方法。

而打开NSException类中会发现 NSSetUncaughtExceptionHandler 方法的参数就是一个 NSException 对象。

@private
NSString name;
NSString
reason;
NSDictionary *userInfo;
id reserved;

私有属性reson就是我之前常见的报错内容

回归到自己的项目中,也发现有这样的异常处理。通常处理如同NSSetUncaughtExceptionHandler处理异常

天下的Crash有几门派?

  • 内存问题

BAD_ACCESS 访问的对象已经释放了,或者重复释放同一对象,出现了野指针的现象。出现这种错误比较难发现。

在内存方面,存在着 野指针 僵尸对象 内存泄漏 诸多问题都会导致崩溃。参考浅谈iOS Crash(二)

处理方式:

  1. 全局断点快速定位代码行
  2. 可以通过Xcode打开 Zombie Objects,也可以使用instruction中的Zombies工具,原理就是僵尸对象来代替已释放对象,根据僵尸对象错误日志定位问题
  3. 调试野指针利器 Address sanitizer 也是利用Xcode中 Address sanitizer
  4. 重写object的 respondsToSelector 方法,现实出现EXEC_BAD_ACCESS前访问的最后一个object
  • 多线程问题

多线程也很容易造成崩溃。之前出现过循环请求导致内存暴增,多线程有时最终也是内存问题。使用多线程参考iOS多线程经典崩溃

最近的项目中使用了响应式编程,开发中出现了Crash,不知道哪里出现了问题。一方面要学会看懂崩溃日志来定位,一方面善于利用Xcode调试工具来发现问题。

最后,追溯源头一部分是自己代码写的有问题。有些问题很容易避免,譬如:
使用字面量,若存在nil,抛出异常
注册观察者未释放,抛出异常
数组越界,抛出异常
返回的数据类型不同,抛出异常

参考阅读

iOS崩溃crash大解析
漫谈iOS Crash收集框架
如何定位Obj-C野指针随机Crash(一):先提高野指针Crash率
如何定位Obj-C野指针随机Crash(二):让非必现Crash变成必现

感谢分享者