作者|潘文超(开风)
出品|阿里巴巴新零售淘系技术部
导读:本文是作者在 「Top100全球软件案例研究峰会」上分享的——手淘Native治理,结合分享后的反馈焦点,从 native 问题线下发现和快速定位、新so集成标准、线上历史native问题治理等几个方面为大家介绍,特产此文。
扫描下方二维码,关注「淘系技术」微信公众号,回复“native”即可获取本次分享完整版 PPT 资料!
背景
无线客户端 crash 一般分为 java crash 和 native crash ,无线应用往往为了追求更好的性能,把一些复杂的计算放到 native 层去实现,java 层通过 jni 调用 native 层实现,满足功能场景;在 native 层产生的崩溃就产生了 native crash ;无线客户端衡量稳定性的最重要的指标就是 crash 率,稳定性一直是各系统治理的重中之重,也是一直绕不开的话题,而 native 是目前业界认为治理最有难度,也是要重点突破的方向。接下来分析一下为什么 native 治理值得去做以及如何做好。
▐ 目前手淘Android的crash现状——找方向
从图中我们可以看出,java crash 正常可以维持在较好的水平,手淘 native crash 一般比 java crash 要高,大促期间,由于手淘内存瓶颈, native crash 率会涨到日常水准的2-3倍。
从数据可见,native crash 是 java crash 的6倍之多,如果要想进一步突破,native 是有很大空间的,但 native 问题一般都很难定位, 堆栈不全,或者堆栈都集中在系统 so 上,无法直接定位问题,所以想要突破难度很大。手淘稳定性再上升一个台阶,native crash是瓶颈,需要突破。
▐ native crash 治理挑战——难
(1)难点一:crash堆栈目前绝大部分只有系统so,缺乏问题关联的业务模块so,定位问题难度大,可以看一下如下的一个native crash堆栈,堆栈中的so都是系统的,无法直接定位业务问题。
(2)难点二:线上so都是去符号化的,即使堆栈中有业务so,也需要记录该APP版本对应的符号化so做反解才能拿到能看得懂的堆栈。这点已经通过第一阶段的native工程标准化解决,打出来的SDK包里面必须要有对应的符号化so才可以集成。
(3)难点三:目前线下有效提前发现native问题的手段缺乏,想要提前发现,需要平台工具和有效手段。
▐ native crash 治理核心问题是什么?——找抓手
要治理、要解决问题,首先得理清目前导致 native crash 的问题,在做之前,做了一下 crash 数据分析,于是手动捞取了当时近5个版本的 top native crash 数据,占比最多的就是sig 6和sig 11。
那能说明什么问题呢?signal 6这种崩溃信号要看具体场景,但根据具体数据分析,手淘里面一般都是堆栈溢出、OOM 等导致的。signal 11 这种崩溃基本就锁定为内存问题了。
根据实际数据,大部分 crash 原因是因为内存,可以初步下的结论是,目前手淘 native crash 治理的关键是内存,解决手淘native内存相关的问题即可解决掉不部分问题。
Native问题治理平台工具调研
对集团内及业界的一些产品做了一些调研,详细如下:
分别从使用成本、功能支撑、是否有堆栈能力,性能如何等维度进行了比较,其实我们的诉求是希望不需要 root 就能 run 起来,因为我们要持续集成、线上能灰度验证,线下可以大规模任务执行、并且可以做手淘 native 问题沉淀,能把问题沉淀做成检查项,可以涵盖解决主要的内存问题,不止是内存泄漏。因此开发了Native Finder,希望能彻底治理好手淘 Native 问题。
Native治理——Native Finder整体技术方案
Native Finder是利用elf hook的原理,对malloc、free、realloc、alloc、mmap、munmap 等操作进行 hook,在自己的 hook 函数中,做一些智能分析和统计,并最后会调用系统内存操作函数,不破坏 so 原本发起的 malloc 等操作。
这个方案的缺点是会有一定的性能损耗,毕竟在 malloc 等操作中增加了一些分析和统计操作,但性能影响还好,在开了堆栈能力之后,APP性能会受影响,这个也是后面要优化的地方。整体技术方案如下:
native crash治理过程
首先在前期,花了比较多时间去研究历史数据及问题,认真分析 crash 的关键问题和痛点是什么,才找准了方向,分析出来内存问题是最痛的点。治理过程总结如上图,分为5个阶段。接一下讲详细介绍结合Native Finder工具平台的治理过程和心得。
▐ native工程标准化
治理总结如下:
总结起来这个阶段我们做了3件事情:
第一,库迁移,为什么要做库迁移呢?我们把老的gnu C++基础库迁移成libc++_ shared库,所有so都做统一,归一化,方便归一native层问题;
第二,我们还做了重复so治理,因为不同so可能依赖了相同的so基础库,举个例子,例如A so依赖了libopenSsl基础so,B so也依赖了libopenSsl库,但他们依赖的版本不同,这样带来的坏处是,首先会增加包大小,其次会有相同so的不同版本存在应用中,这给定位问题带来了麻烦,所以需要对基础so去重。
第三,每个版本包包括灰度版本都需要存储下对应的符号化so,便于在crash发生后,我们对堆栈做符号化处理,这样堆栈我们就能看懂了,加快和精准定位问题。这个阶段是后面做的所有事情的基础,非常重要。接下来我们看看下一个阶段治理
▐ Native Finder开发完成,线下monkey跑native问题
此阶段发现了几个堆破坏的问题,但是经过好几天反复线下执行 monkey,并未有任何进展。
后续调整思路,开始逐个分析线上存在的 native crash,并根据这些 crash 特征和根因开始沉淀经典问题,并把这些问题做成检查项,跟同学交流和对焦后。
通过进一步的数据,发现内存 OOM 是目前优先级较高,且比较严重的问题,所以开始做这方面的技术建设,跟 crashSDK 打通,Native Finder 中统计和分析 so 维度占用内存未释放的数据,在 crash 的时候做内存信息 dump,并输出辅助信息,例如 malloc、mmap 次数、大内存(大于2M,属于大内存申请,可配置,可动态调整)的申请等信息。接下来看一下线下monkey 驱动阶段
▐ 线上灰度,结合用户真实操作场景crash
线下 monkey 并不能都能复现问题,借助工具平台拿到关键信息去做问题解决和定位,我们希望场景更加丰富和多样,所以我们把 Native Finder 放到线上,做了线上灰度。
随即把 Native Finder 放到线上做外灰,在用户真实操作场景下的 crash,拿到 crash 时的内存 dump,但是经过一段时间的线上 crash 内存信息采集,然后分析之后,没发现明显问题,从现在回头看这个阶段,其实当时的数据是能够体现出问题的,只是当时的想法不对。
▐ 虚拟内存不足,是目前OOM主要原因
我们对线上crash做了分析,同时也在线下做了可疑场景的尝试复现,复现过程中,我们也做了大量数据的对比分析;
分析发现:正常 crash 跟 native oom crash,在内存详细数据上做对比,发现OOM crash 在 native vmsize 上有较大差异,又看了很多手淘 OOM crash,发现都是这个原因,vmsize 暴涨。
大家都知道,32 位系统下,系统 vmszie 只有4G,还要抛去一些系统内核占用、以及共享内存占用,vmsize比较有限,手淘又是一个体量很大的航空母舰,各个业务都想有最佳的业务体验,都想用空间换时间,每个业务泄漏那么一点,那手淘就被撑爆了,是累加泄漏的结果。
所以手淘 Android OOM 要一个一个解决,逐个挖出来,才能根治。我们整个过程沉淀了如下检查项:一共沉淀了8项内存检查,内存检查项已经能覆盖 80% 以上的内存问题了;fd 文件句柄检查项一共沉淀了6项,fd 的检查项已经能覆盖几乎95%以上的 fd 问题了。
我们同时也研发了本地调试模式,方便开发和测试同学,能快速在本地复现和定位问题,具体的技术方案如下:
▐ 开始陆续发现各种 native 问题
朝着这个方向,对 Native Finder 做了逐步优化,开始陆续发现各种问题,治理初步阶段,我们通过 Native Finder 工具平台一共治理发现 20+ 问题,其中包括了多种问题类型,例如内存堆破坏、内存泄漏、OOM、内存操作越界、多次free、内存操作错误等。
同时手淘日常的 native crash 率也有明显降低。到这里,我们 native crash 已经初见成效。虽然通过治理,陆续发现了不少问题,但是还远远不够,手淘内存问题依然严峻,特别是双十一场景下,互动、活动以及各种场景链路互拉的场景,内存问题还是很严峻,后续还需更加努力。
展望
接下来我们希望还能做的更多,现在才刚刚开始;手淘内存问题依然严峻,要彻底治理,需要建立卡口,发现问题自动加入必改问题池,形成良性循环,旧问题不断发现解决的同时,还需要杜绝新问题的引入。
除了 native so 导致的内存问题,当前 H5 场景的内存问题也比较严峻,去手淘随便拿几个 H5 页面,看一下内存增量,都超过内存标准,H5缺乏管控,下半年需要对H5内存做卡口严控;目前针对前端的内存泄漏,还没有有效的手段去检测发现,从native层看,都体现在内核上,内核应该是没有问题的,如果有效发现前端代码导致的内存泄漏,也是一个值得研究的点,不过先做卡口再做进一步突破。
今日吐槽
大家都在 native 治理上遇到哪些坑?
欢迎评论区留言,和小橙子分享哦~
We are hiring
淘系技术质量团队负责保障整个淘宝和天猫主站的业务质量,在这里有丰富多样的业务场景和技术挑战,以及很多优秀的合作伙伴。在这里你不仅能够了解世界级双十一是如何保障的,最关键的是有对技术极致追求,对生活的充满热爱的一群俊男美女们。
还等什么,赶紧加入我们一起共同打造淘系的技术质量。
请投递简历至邮箱:hane.yjr@alibaba-inc.com
关注【淘系技术】,一个有内容,有温度的微信公众号!