Crash 基础概念

什么是 Crash

Crash,说白了就是程序突然“死”了。用户正用着手机呢,屏幕一卡,然后“嘣”一下回到桌面——这就是典型的 Crash。从技术上讲,Crash 是应用遇到了无法恢复的异常,操作系统被迫把进程杀掉。

我在项目中遇到过最夸张的一次,某个版本上线后 Crash 率飙升到 15%。查了半天,发现是一行代码里的野指针。你看,一个小小的指针没处理好,就能让整个产品崩掉。

Crash 的本质: 程序执行了非法操作,触发了操作系统或虚拟机的异常处理机制,最终导致进程终止。

常见的触发场景包括:

  • 访问了已经释放的内存(野指针、悬空指针)
  • 数组下标越界(比如只有 10 个元素,你去访问第 11 个)
  • 多线程数据竞争(两个线程同时写同一个变量)
  • 空指针调用(你调用了一个 null 对象的方法)
  • 堆内存耗尽(OOM,Out of Memory)

Crash 的影响有多严重?

可能有人觉得“崩一下也没啥大不了”,重启就好了。但真实情况远没那么简单。

影响维度 具体表现 我的经验值
用户体验 用户流失、差评、卸载 Crash 率每上升 1%,日活可能掉 2%~5%
业务收入 支付中断、广告损失、订阅退费 我之前负责的电商 App,Crash 导致下单页崩溃,一晚上损失了十几万 GMV
开发者口碑 应用商店评分下降,品牌受损 某次紧急发版修复后,用户评论“终于不闪退了”
研发效率 需要投入大量人力排查和修复 最头疼的是“偶发 Crash”,埋点都拿不到堆栈

避坑指南: 我曾经因为忽略了一个只在 Android 12 上出现的 Crash,导致灰度发布时炸了一半的用户。从此我再也不敢只看 top crash 列表,那些低频但重复出现的异常也要重视。

Crash 分类概览

Crash 种类很多,但咱们做复现框架,必须先学会分类。只有分对了类,才能针对性设计复现策略。我个人习惯按根本原因分这几类:

  • 内存类 Crash:野指针、空指针、内存泄漏、释放后使用(Use-After-Free)、缓冲区溢出。这类最头疼,因为崩溃点往往离真正出错的地方很远。
  • 逻辑类 Crash:数组越界、类型转换错误、除零、死循环导致 ANR(应用无响应)。这类相对容易复现,加断言就能抓到。
  • 并发类 Crash:线程安全(死锁、活锁)、数据竞争、ABA 问题、线程池耗尽。我遇到过最邪门的是在春运峰值 QPS 下才复现的并发 Bug,本地跑一万次都正常。
  • 资源类 Crash:OOM(堆、栈、文件描述符耗尽)、数据库锁、网络超时连锁反应。这类在低端机型上特别多。
  • 平台/环境类 Crash:系统 API 变更、第三方 SDK 兼容性、厂商定制 ROM 差异。说实话,这种问题只能靠线上监控和灰度备份。

有了分类,你就能一眼看出问题的“家族”。比如同样是 SIGSEGV,可能是野指针也可能是空指针——但处理思路完全不同。

Crash 分类与复现框架核心结构 Crash 分类体系 内存类 Crash 逻辑类 Crash 并发类 Crash 资源类 Crash 环境类 Crash 野指针 空指针 内存泄漏 Use-After-Free 数组越界 类型转换错 除零/死循环 死锁/活锁 数据竞争 线程池耗尽 OOM(堆) 栈溢出 FD 耗尽 系统 API 变更 SDK 兼容 厂商定制 ROM 复现框架设计核心思路 先分类 → 再制定复现策略 → 自动化注入或条件触发 内存类用 AddressSanitizer / 并发类用 TSAN / 资源类用压力测试

个人习惯: 我每次拿到一个新 Crash 报告,第一件事不是看堆栈,而是先看它属于哪一类。然后脑子里自动匹配该类的复现套路。比如,内存类先 check 是否开启了 ASAN,并发类先看线程日志。

注意: 很多 Crash 表面上属于一类,根因可能跨类。比如 OOM 有时候是内存泄漏(内存类),有时候是图片加载太多(资源类),还有时候是线程栈溢出(逻辑/资源混合)。所以分类并不是的,但框架得先有个骨架。

从分类到复现 — 我们要做什么?

分类只是第一步。接下来我们要搭建复现框架,需要针对每一类设计不同的复现手段。举个例子:

  • 内存类 Crash:用 AddressSanitizer 或 Valgrind 很容易捕捉,但线上环境不能开这些工具。所以我们得在代码层加 Hook 或者用 MMKV 模拟内存压力。
  • 并发类 Crash:用线程安全检查工具(TSAN),或者通过增加线程数、降低 sleep 时间来触发竞争。
  • 资源类 Crash:模拟低内存、低磁盘、慢网速环境,用手动触发系统 GC。
  • 环境类 Crash:只能在真机集群上跑自动化 Monkey 测试,覆盖不同系统版本和厂商。

这章先把分类讲清楚。后面的章节,我会手把手带你搭一个通用的复现框架。你想想看,一旦有了这个框架,再棘手的 Crash 你也能快速复现出来,然后修复它就只是时间问题了。