Fabric 是业界著名的 crash 监控平台,国内外均有不少 app 使用 Fabric 进行 crash 和其他稳定性数据的监控。其中,OOM 率数据也是深受大家关注的数据之一。
但现在,我们通过各 app 间 OOM 率对比、猜测和验证,实锤证明了 Fabric 的 OOM 率有重大误报问题。其中最主要的误报是:Fabric 将用户正常的后台启动误判为了 OOM,导致各 app 的 OOM 率均是大幅偏高的。
OOM 率对比
Fabric 检测 OOM 的原理,参考自 Facebook 的一篇文章:https://code.fb.com/ios/reducing-fooms-in-the-facebook-ios-app/
它在 app 每次启动时,判断了 app 上次进程结束的原因,排除掉 首次安装、app升级、系统升级、crash等原因,最后筛选出前台 OOM 的用户。
Fabric也在文档中特意强调,他们的 OOM-free-session 指标,使用的是前台 OOM 率。也就是说,被 Fabric 捕获到的 OOM 用户,其用户体验预期是与 crash 同样严重的。
We only report the OOM if the app was in the foreground before the second launch.
但我们经手的多个产品,在 Fabric 平台上体现的 OOM 率,都比直观感受高很多,在百分之的量级。并且多个产品之间的 OOM 率有明显差距。如果线上用户的实际体验真是如此,那么 OOM 问题的确是非常严重、亟待解决的问题。
猜测
为了定位 OOM 问题,我们曾根据 Facebook 描述的原理,自研过 OOM 监控功能。我们期望通过追查单个用户 OOM 前的操作行为去定位 OOM 发生场景的共性。但当时,我们惊奇地发现,很多用户的行为是:启动 - 再次启动。看起来是用户在启动阶段,就遭遇了 OOM 问题。
这样的用户行为给我们带来了很大困扰。直到我们发现,自研的 OOM 监控中,默认将 app 启动后的状态置为了 foreground 状态。从代码上推测,当用户因 background fetch 等机制触发后台启动时,就有可能被自研 OOM 监控模块判定为 OOM。
对此,我们快速进行了验证,发现,后台启动的确会被自研 OOM 监控判定为前台 OOM。修复这一问题后,我们也对比发现,Fabric 的 OOM 率和 自研组件监控到的OOM率,相差甚远。
于是我们怀疑,Fabric 是不是和我们一开始犯了同样的错误,默认 app 启动后即进入前台,从而将后台启动误判为 OOM 呢?
验证
我们对于以上猜测进行了验证。
由于 Fabric 的 OOM 数据,只有 “版本的 OOM-free-session” 这一项,没有提供更详细的信息,也无法单点追查,我们只能通过打一个特殊版本号的包的方式实验。
至于如何让 app 后台唤起,我们使用的是推送带选项通知的手段。用户在通知中心做这些操作,实际会让 app 在后台短暂唤起。
用这个特殊版本号的包,操作了若干次后台唤起。两天后,我们果然在 Fabric 平台上看到了这个特殊版本号的包,被检测到了 5 次 OOM。但实际上,整个过程中,此包没有遇到任何一次真正的前台 OOM。
据此,我们可以证明,Fabric 至少将用户正常的后台唤起,误报为了 OOM。这显然会造成严重的 OOM 率虚高问题。
与我们有同样困扰的开发者也存在,在追查期间,我们也在 StackOverFlow 上找到了类似的讨论:https://stackoverflow.com/questions/48121843/suddenly-getting-many-fabric-out-of-memory-sessions-can-fabric-oom-reports-ever
而除了将正常后台唤起误报为 OOM 之外,我们从原理和文档上还能判断出,Fabric 至少还将 exit 和 watchdog 误报成了 OOM。