《全民K歌内存篇1——线上监控与综合治理》《全民K歌内存篇2——虚拟内存浅析》《全民K歌内存篇3——native内存分析与监控》一、背景
在年的上半年,我们在用户反馈后台发现闪退、白屏问题不断增多,这些问题严重影响用户体验。观察Crash监控平台发现Crash率也在逐步升高,其中Native层的Top1的crash堆栈信息如下:
这个Crash在整体的crash中占比很大,通过这个堆栈信息,发现并没有明显的指向哪个业务代码。此时,把发生Crash时的内存信息上报到后台,分析发现:Crash发生时虚拟内存非常接近4G。
以及日志信息:
为此,我们通过脚本模拟用户在不同业务场景反复进出运行,发现内存水位在逐步上升,当接近4G时,复现了该crash。在前期,我们解决了一些专项测试同学提出的内存问题,但是内存水位依然维持较高状态,Crash率也没有得到有效缓解。
经过粗略分析,发现应用内内存占用的大头在native层。那么,该如何系统的分析和解决Native内存问题呢?
二、问题分析2.1为什么会内存不足
Android系统是基于Linux之上的,在内存管理上基本一致,但也有差异。简化后如下图所示:
在Android手机上,内存的使用受操作系统和内存硬件设备限制,这里以32位的应用运行在8G内存、64位系统的手机上为例,总结几点如下:
虚拟内存:每个进程都有独立的虚拟内存空间,进程能够访问的也只能是虚拟内存地址,它的大小由操作系统决定,32位系统则限制在4G以内;
物理内存:是实实在在存储数据的物理模块,它的大小由设备本身决定。所有应用APP可用内存=内存硬件总大小-操作系统内核占用部分(一般小于1G);
ZRAM区:不像Linux系统,长期不访问的内存块可以将内存数据交换到磁盘,从而释放出这部分内存空间。Android的系统是通过在内存中开辟一块独立的ZRAM区域,当需要交换时,内存只是被压缩并交换到ZRAM区。这就决定了可用内存永远不能超过8G;
虚拟内存区块数:虚拟内存申请时,如果已申请的空间不足,会开辟一块新的虚拟内存区块。区块数默认限制以内,可以通过读系统文件/proc/sys/vm/max_map_count查看。
2.2内存分布情况分析
通过adbrun-asxxx.xxx.xxxcat/proc/pid/smaps命令,可以获取到系统的smaps文件,该文件详细记录了应用虚拟内存的分配情况。分析可知:左侧12c-13d代表的是一个虚拟内存区块,右侧[anonalvik-mainspace]表示这一块内存由JVM虚拟机所申请。如下图可知:虚拟内存主要由虚拟机、系统库文件、应用dex文件,以及业务调用libc.so的malloc所申请。
接着,对smaps文件的pss数据(实际占有的物理内存)进行统计分析,如下图是K歌直播场景内存分布情况:
分析发现,业务申请的内存主要分布在两部分,即/p>
程序文件/p>
占比:应用的.dex文件(占35%)、加载的so文件(占7%)
解决方案:
删减代码,减少dex文件内存占用:K歌内有许多旧代码实际已经废弃,可以将其删除。这里的优化是一个持续的过程,其中歌房在一次代码整理之后就删除了8W多行代码。
按需加载,减少so文件内存占用:通过smap文件发现,部分加载到内存的so实际是无需运行的,例如直播观众端不需要使用美颜相关的功能,这里可判断仅主播端才加载相关so,大大减少so文件带来的内存开销。
NativeHeap/p>
占比:业务集成的so库内申请和图片(8.0及以上版本)共占39%
解决方案:检测、监控申请内存的业务,修复不合理申请。
面临困难:不像Java内存有系统支持的内存快照文件,分析起来非常方便。Native内存分析就显得非常困难,后续内容将围绕So库与图片内存问题展开叙述。
三、So库内存检测与分析3.1Native内存分析工具对比1)、内存总量分析工具
在团队内,通常用Perfdog来检测应用程序内存问题,这个工具的实现原理是不断的读取系统的内存值。通过Perfdog,我们只能观察内存总量,去判断是否存在内存异常问题。可是,Perfdog无法提供有效的堆栈信息,帮助开发定位问题所在。如下图所示,是在测试K歌直播上下滑场景过程中的内存数据,发现nativePss在不断上涨。
2)、内存分量分析工具
经过调研发现,Android分析native层内存工具,有Android原生支持的,也有开源的。整理如下表/p>工具基本原理能力使用方法优势劣势malloc_debug替换libc.so的malloc、free等函数;1、检测内存申请和释放情况,2、回溯堆栈;系统自带功能,无需集成,adb命令行指令;1、无需开发;2、能够还原部分系统堆栈;1、仅支持已root手机;2、分析结果无法准确识别业务问题;perfettoheapprofd;1、检测内存申请和释放情况,2、回溯堆栈;无需集成,adb命令或者webui界面操作。1、无需开发;2、能够还原部分系统堆栈;1、仅Android10以上支持;2、分析结果无法准确识别业务问题;loli_profilerhooklibc.so的malloc,free等函数;1、检测内存申请和释放情况,2、可以回溯堆栈;无需集成,adb连接PC端工具即可检测;1、无需开发;2、可以指定SO分析;1、必须连接PC端工具;2、使用不灵活方便;
对比上述工具,结合使用经验,小结如下:
malloc_debug/p>
Android原生支持,需要root手机才能使用,非常不方便。
启动应用时就会开启检测,无法控制启动时机,使用不灵活。
perfetto(AndroidStudio4.1以后的版本支持native内存检测,底层实现采用的是该方案):
Android原生支持,Android10以上才支持,若Android11及以上手机可以直接使用web端工具调试,体验链接