Crash(崩溃)的定义、分类与计算口径

聊稳定性,第一个要讲的就是 Crash。说白了,Crash 就是应用因未捕获的异常或系统级错误而意外终止。用户看到的是「App 突然没了」、或者直接回到桌面,严重的甚至整机重启。

我在项目中遇到过不少 Crash,但早期我其实没太区分「Java 崩溃」和「Native 崩溃」——总觉得都是崩溃,算一个数就行了。后来被线上问题教育了一顿:有一次大量用户反馈「解锁后屏幕黑几秒才恢复」,查了好久才发现是 System Server 里一个 Native 指针越界导致的。从那以后,我对 Crash 的分类就特别上心了。

1. Crash 的定义

从 Android 系统角度看,Crash 指 进程因不可恢复的错误而异常退出。这个错误可以来自 Java 层(比如 NullPointerException),也可以来自 Native 层(比如 SIGSEGV)。系统会捕获这些信号,生成 tombstone 文件(Native)或写入 DropBox(Java),最终弹出「App 已停止运行」的对话框。

💡 一个小细节:如果应用在前台崩溃,用户会直接感知;如果退到后台后崩溃(比如 Service 异常),有时用户不会立刻察觉到,但指标上仍然算一次 Crash。

2. Crash 类型:Java 与 Native

Java 和 Native 崩溃的捕获机制、堆栈格式、排查工具完全不同。你想想看,Java 崩溃我们能直接看到异常类型和调用链,而 Native 崩溃看到的是一堆寄存器值和信号码——处理起来像换了一门语言。

维度Java CrashNative Crash
触发原因未捕获的 Java 异常(Throwable)信号机制(SIGSEGV、SIGABRT 等)
常见场景NullPointer、IndexOutOfBounds、ClassCast、OOM指针野、堆破坏、JNI 滥用、系统库崩溃
捕获机制Java 层 UncaughtExceptionHandlerLinux 信号处理器 + debuggerd
堆栈信息完整的 Java 调用栈寄存器 + 函数地址(需 addr2line 或 ndk-stack)
错误文件DropBox / logcattombstone / logcat

这里提个我踩过的坑:我一直以为只要监测 UncaughtExceptionHandler 就行了,直到有一天我发现一部分 Crash 根本没被捕获——原来是 Native 层的 SIGABRT 直接杀掉了进程,Java 层的 handler 连跑的机会都没有。所以做稳定性的朋友,一定要同时监控两种类型。

⚠️ 避坑指南:我曾经只统计 Java 层的「崩溃率」,结果线上明明有 0.5% 的 Native 崩溃,我看的指标却一直是 0.1%。后来花了三天才把 Native 采集渠道补上——别学我。

3. 崩溃率计算口径

定义清楚 Crash 之后,怎么算「崩溃率」?我见过很多团队口径不统一,导致两个版本的数据差了 2 倍。所以咱得把这几个口径掰清楚。

3.1 用户影响口径(用户级崩溃率)

公式很简单:

用户级崩溃率 = 发生至少一次 Crash 的用户数 / 日活跃或月活跃用户数 × 100%

这个口径反映的是 「有多少比例的用户受到了崩溃影响」,而不是「崩溃的严重程度」。我建议线上核心指标用这个,因为一个用户一天崩 10 次和崩 1 次,对用户体验的伤害程度是不一样的,但「受影响的用户数量」直接决定了口碑扩散范围。

3.2 会话口径(Session 崩溃率)

Session 崩溃率 = 导致 session 异常结束的 Crash 次数 / 总 Session 数 × 100%

这里要定义什么是 Session。一般从应用启动开始,到应用进入后台超过 30 秒(或主动退出)结束。如果一个 Session 内发生了 Crash,就算一次崩溃 Session。这个口径 能更好地衡量崩溃对用户使用流程的打断程度。

3.3 启动口径(Startup 崩溃率)

启动崩溃率 = 应用启动后 N 秒内发生 Crash 的次数 / 启动总次数 × 100%

N 通常取 5 秒或 10 秒。启动阶段的崩溃 对用户伤害最大——一打开就闪退,用户很可能直接卸载。

🔑 重点总结:我个人习惯按 「用户影响口径」+「Session 口径」双指标看。一个看广度,一个看频次。两个差了 3 倍以上时,说明少数用户重复崩溃得很厉害,需要排查「用户修复方案」。至于启动崩溃率,我通常单独挂在「第一屏监控」上。

哦对了,还有一种计算方式叫 「崩溃次数 / DAU」,这个不是真正的「率」,而是「人均崩溃次数」。某些游戏团队喜欢这么用,但我不推荐作为稳定性核心指标,容易稀释掉「用户受影响」这个关键信息。

Crash 稳定性指标框架 崩溃 (Crash) 指标 1. 定义 进程因不可恢复错误异常退出 如 NullPointer / SIGSEGV / SIGABRT 2. 类型 Java Crash UncaughtException 捕获 Native Crash 信号机制 + debuggerd 3. 计算口径 用户级崩溃率 Crash 用户数 / DAU/MAU Session 崩溃率 崩溃 Session 数 / 总 Session 数 双指标配合使用 💡 个人建议 线上核心:用户级崩溃率(衡量影响广度) 细粒度排查:Session / 启动崩溃率 ⚠️ 我曾经踩过的坑:只追踪 Java 层,漏掉了大量 Native 崩溃 现推荐方案:同时接入 UncaughtExceptionHandler + Breakpad(信号捕获)

4. 不同口径的适用场景

每个口径都不是万能的,我根据自己的实践经验列了个对比 —— 你根据业务选择合适的组合就好:

  • 用户级崩溃率 —— 适用于版本质量看板、发布门禁。我们团队曾经定了个红线:用户级崩溃率 ≤ 0.2% 才能全量发布,超过的话就灰度回滚。
  • Session 崩溃率 —— 适用于衡量「单次体验是否完整」。做广告或支付场景时特别重要,如果一个用户正在付款时崩溃,那不是数据丢失的问题,是收入损失。
  • 启动崩溃率 —— 适用于新版本首次安装后的监控。我有个朋友团队发布了一个版本,启动崩溃率达到 5%,他们 2 小时内就回滚了——及时止损。

⚠️ 注意:计算 Session 崩溃率时,如果 Session 定义不统一(比如我们之前按前台 60 秒后台 10 秒),数据根本无法与行业对标。建议参考 Android Vitals 的 Session 标准:前台运行到后台超过 30 秒则切新 Session。

好了,Crash 的定义、两种类型、三种主要计算口径都讲清楚了。记住核心:不要只看一个数,至少要用户级 + Session 级双层监测。 至于怎么采集、怎么治理,后面的章节会展开。嗯,先消化这些吧。