Crash 模拟与异常捕获概述
大家好,我是这门课的主讲。说实话,干了这么多年移动端稳定性测试,我最大的感触就是——Crash 这玩意儿,你越怕它,它越找你。很多团队把 Crash 率当成 KPI 来追,但真到了线上,用户骂娘的时候,你连复现都复现不出来,那才叫绝望。
我个人习惯是,在项目早期就要主动「搞破坏」。不是真的破坏,而是用可控的手段去模拟崩溃场景,再配上完善的异常捕获机制,把那些藏在犄角旮旯的 bug 提前揪出来。这套方法,我在这门课里会掰开揉碎讲清楚。
为什么我们要学 Crash 模拟?
你想想看,一个 App 上线后闪退,你能拿到什么?通常是几行堆栈、一个模糊的设备型号。够用吗?不够。我遇到过好几次,线上 Crash 堆栈指向的代码行号跟实际发布版本根本不匹配——原因就是符号表没对齐,或者异常没来得及上报。
Crash 模拟,说白了就是在可控环境里制造事故。比如凭空抛一个空指针,或者故意让线程死锁。然后观察你的异常捕获系统能不能接住、怎么接住、接住之后能吐出多少有用信息。只有反复练过这套流程,你到了线上才不会慌。
核心观点:Crash 模拟不是「没事找事」,而是用最小代价提前暴露防御系统的薄弱环节。
我们能学到什么?
这门课总共 30 章,但咱们今天先搭个骨架。我会带你走通下面几个关键点:
- Crash 的分类与触发机制:哪些是系统级(SIGSEGV、SIGABRT),哪些是应用级(NSException、Java Exception)。
- 常见模拟手法:代码注入、运行时修改、内存踩踏、信号触发。每个都有适用场景和坑。
- 异常捕获的最佳实践:从 NSSetUncaughtExceptionHandler 到 signal 处理器,再到 Mach 异常端口。你该用哪一层?
- 日志与符号化:拿到原始堆栈怎么还原成可读的类名、行号?dSYM 和 ProGuard 映射文件怎么管理?
- 自动化测试集成:如何把 Crash 模拟塞进 CI/CD 流程,每次构建后自动跑一轮「破坏测试」?
说实话,这些内容单独拎出来都不难,但串联起来就能形成一套完整的防御体系。
知识体系一览
为了方便你快速建立全局视角,我把本章核心概念画了张图。你一看就明白 Crash 模拟和异常捕获在整个测试流程中的位置:
这张图把课程的主脉络串起来了。你会发现,模拟 -> 捕获 -> 分析 是一个闭环,而最下面是自动化集成,让这个闭环持续运转。我最早做这个方案的时候,光模拟就折腾了两周,结果发现捕获层根本没处理好信号嵌套问题——还好是内部演练,要是线上就惨了。
一些我的个人建议
课程正式开始之前,我想给你三个贴士:
- 别贪多。 别试图在一章里把所有 Crash 类型都模拟一遍。先从最典型的空指针和数组越界入手,跑通流程再说。
- 日志格式要统一。 我见过最头疼的场面:iOS 和 Android 的 Crash 日志字段顺序不一样,解析脚本要写两套。前期就约定好 JSON 规范,后面省大事。
- 符号表一定要归档。 每次发版都把 dSYM 或 mapping 文件存到固定服务器,按版本号命名。我曾经因为忘记保存,线上堆栈全是十六进制地址,两眼一抹黑。
小技巧:模拟 Crash 时最好加一个「安全开关」,比如通过 adb 命令或 Xcode Scheme 参数启用,避免误触到线上环境。我一般用编译宏 #if DEBUG 来隔离。
注意:千万不要在用户侧进行任何 Crash 模拟!所有测试必须在预发布环境或内部构建上进行。有些国家/地区对 App 崩溃率有法律要求,故意制造崩溃可能违反条款。