一次崩溃率暴涨 10 倍的线上事故:从“无堆栈”到精准定位,到光速解决

稳定性,是工程师的生存线。

我在团队中除了负责核心需求开发外,还负责技术创新(前文介绍的KMP)和性能优化(前文介绍的卡顿监控优化),稳定性等。这篇文章想聊一次我经历过的最棘手、最惊心动魄的线上稳定性事故。

它涉及:

  • SIGABRT / EGL_BAD_ALLOC / native 内存 OOM

  • 无业务堆栈、无 debug 信息

  • 大规模真实用户、不可回滚的线上互动功能

  • 多团队协作 & 错位 blame

  • 热修复策略受限 + 紧急曲线救国

更重要的是,如何从海量日志 + 极端场景 + 业务行为分析 中"抓到最后一根稻草",并把它证明成唯一真相。我负责项目的整体稳定性,Bugly 实时监控,Native 崩溃跟踪,灰度风险验证,历史问题溯源 & 定点治理。我每天到公司第一件事就是先看Bugly,跑我写的分析脚本,查看告警,了解我们的产品质量。

背景:直播互动场景复杂,稳定性责任重大

在我们教育直播 App 里,直播间有"小组讨论"场景:每个小组 6 人,平时只拉老师和课件流,老师触发互动 → 学生开始拉同组同学的音视频流,讨论结束 → 关闭拉流。看似普通需求,但它涉及动态 RTC 路径切换、频繁 Surface 创建/销毁、底层内存抖动

当问题发生时,我必须第一时间识别、定位、响应。

事故:崩溃率一天暴涨 10 倍

某天晚上正在写代码的我,收到了bugly的报警:App 崩溃率突然大幅跃升,且集中在同一直播课程类型。我们第二天的整体崩溃率直接拉升了10倍。 Bugly 报警如下:

ini 复制代码
SIGABRT

Failed to create context, error = EGL_BAD_ALLOC

-   0

    #00 pc 00000000000a8904 /apex/com.android.runtime/lib64/bionic/libc.so (abort+164) [arm64-v8a::a7f4c875f4091d6d01501d20016ac2a8]

-   11

    #11 pc 00000000000ac350 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) [arm64-v8a::a7f4c875f4091d6d01501d20016ac2a8]

堆栈近乎没有业务信息:一个字: 。我立马意识到,这不是常见的 Java OOM,而是: EGL_BAD_ALLOC = 显存/Surface 资源耗尽 → native OOM 。再结合 SIGABRT,非常明确:某个 native 资源未释放,导致 EGL 环境创建失败

但崩溃堆栈里没有明确业务代码,没有 RTC 相关调用,没有 Cocos 痕迹,没有崩溃上下文。这是最难排的一类事故:无栈 + native + 难复现

第一步:从日志里"复盘用户的一天"

我们有实时上传的全量日志 (自研接入链路),我抽取多个崩溃用户完整课时日志轨迹

包括session 行为序列,课程类型,设备内存变化,拉流与 Surface 生命周期,垃圾回收行为,CPU/MEM 峰值点

发现:

观察点 结果
崩溃设备 分散,无设备集中问题
发生场景 用户都做过新的互动(动态拉同组流,且互动了多次),还有Cocos题,H5互动题等
内存趋势 PSS 持续上升,峰值后立即崩溃
用户行为 不集中(说明不是单场景代码 crash)

第二步:锁定"共性" → 不断假设 &证伪

我第一时间把怀疑点定位到我们的新互动题上(拉关同组所有人视频流,且互动了多次)。我们业务的几个内存消耗大户,流媒体,Cocos互动题,H5互动题,以前都发生过较为严重的内存泄漏。因为我负责直播间的播放器和流媒体的开发,且新上线的这个互动和流媒体重度相关,所以第一时间拉流媒体老师排查。如果流媒体没问题,则下一步需要去找Cocos团队和FE团队确认业务变更。崩溃堆栈的不明确,给问题的解决带来了巨大困难。

我将崩溃日志按课堂维度进行聚类分析(我们业务规模足够大):

场景 崩溃比例
普通直播 几乎无崩溃
带小组讨论课堂 集中出现

这就让我意识到: 崩溃与小组音视频"动态拉流"强相关 。说明我刚开始的怀疑方向是对的。 这是典型内存泄漏 + 场景触发 + 极端堆叠

第三步:复现:一次复现就能锁死真凶

我用测试账号密集操作拉同组流这个互动 ,并观察:PSS 变化,Surface 数量,EGL context 数量,GPU 内存占用。最终成功复现: 每次互动讨论 → Surface 未释放 → 累计增长 → EGL 内存耗尽 → 崩溃。

抓到真凶了。

第四步:多团队共查 → 二分删代码确认

拉上流媒体负责人一起排查,是他们最近上线的一个拉流优化 导致:老师结束互动时,学生 Surface 对象没有释放 ,而这一优化是最近一个版本才上线,我们开发联调阶段根本没接到这段代码****

第五步:热修复?不够!只能曲线救国

问题出在 C++ 层,我们的热修复只能 patch Kotlin 层。怎么办?我想了一个策略,下发kotlin热修复包,更改互动逻辑。业务上层只拉用户音频流,不拉视频流。用户无感,虽然功能降级但彻底避免崩溃 同时:紧急修复bug, 小比例强升版本。针对课程粒度大规模推送。最终崩溃曲线极速回落

事故总结:定位思路与方法论

1. 先判断类型

EGL_BAD_ALLOC = GPU/Surface 泄漏

2. 用用户行为还原现场

日志复盘用户的行为

3. 找共性

跨用户 + 跨课程聚类

4. 激进复现

模拟真实课堂、重复操作

5. 找到"最后一根稻草

OOM 永远不是最终崩点,而是"积累崩溃模型"

6. 架构级降级策略

必要时牺牲体验换活着

教育直播类 App 稳定性体系

类目 手段
监控 Bugly、自研全量日志、PSS/Surface 监控、native signal 处理
定位 日志链路复原、行为聚类、设备维度剥离、二分验证
治理机制 Feature Flag、动态策略、灰度实验、强升
研发规范 RTC 场景 Surface 生命周期 checklist、C++ 资源自测脚本
演练 内存 stress 测试、极端设备测试、反复操作场景

特别适用于RTC + 多引擎 + 多端融合的业务场景。

崩溃率暴涨不可怕,可怕的是没有应对危机情况的能力

稳定性不是"碰运气",是系统工程,它涉及

  • 全链路监控
  • 行为洞察能力
  • 技术直觉
  • 极致复现
  • 果断降级
  • 多团队推动能力

这次经历让我更加深刻地理解:稳定性建设不是一次性的任务,而是一种长期的工程方法论。它要求我们在日常开发中不断思考、优化和预防,也促使团队形成科学的事故响应流程、复盘机制和可量化的稳定性指标。正是这种不断迭代和沉淀的能力,帮助我们在复杂业务场景下保持产品可靠,同时也提升了每一位工程师面对未知挑战时的判断力与执行力。

相关推荐
踏雪羽翼1 天前
android TextView实现文字字符不同方向显示
android·自定义view·textview方向·文字方向·textview文字显示方向·文字旋转·textview文字旋转
lxysbly1 天前
安卓玩MRP冒泡游戏:模拟器下载与使用方法
android·游戏
夏沫琅琊1 天前
Android 各类日志全面解析(含特点、分析方法、实战案例)
android
程序员JerrySUN1 天前
OP-TEE + YOLOv8:从“加密权重”到“内存中解密并推理”的完整实战记录
android·java·开发语言·redis·yolo·架构
TeleostNaCl1 天前
Android | 启用 TextView 跑马灯效果的方法
android·经验分享·android runtime
TheNextByte11 天前
Android USB文件传输无法使用?5种解决方法
android
quanyechacsdn1 天前
Android Studio创建库文件用jitpack构建后使用implementation方式引用
android·ide·kotlin·android studio·implementation·android 库文件·使用jitpack
程序员陆业聪2 天前
聊聊2026年Android开发会是什么样
android
编程大师哥2 天前
Android分层
android
极客小云2 天前
【深入理解 Android 中的 build.gradle 文件】
android·安卓·安全架构·安全性测试