Version information
https://about:blank/
Date | Descritpion | More info. |
2023-8 | 适配Android U Note: /odm下的vendor进程暂不支持 | 8-10, u-pre MERGED |
2023-7 | 添加对Vendor进程的支持 | 7-25, t-pre MERGED |
2023-4 |
| 3-28, t-pre MERGED |
2022-10 | Document creation |
查看native堆内存的使用、常规手段一般可以借助meminfo获取native堆对应的memory map和malloc info.信息,体现出PSS占用的数据和堆分配器内部的统计,但却无法直接和业务侧的使用情况相关联。
比如native OOM问题,meminfo仅能给出该业务在问题发生时的内存使用数值,但无法分析该业务的哪部分逻辑在使用,使用了多久、多大、多少次。malloc_debug是当前排查此类问题或查看堆内存使用的一种手段,但它较差的运行时性能、繁琐的分析步骤也一直限制其应用场景和使用范围。
-
功能与特点
基于上述痛点和需求,Android T上我们集成了自研的Native Heap Insight工具,用以分析和报告运行时的堆内存使用情况,它的优势体现如下:
较低的性能延迟 -- M2上验证system_server、其malloc平均延迟为 ~5 us;在相同测试维度下相较malloc_debug有数倍以上的提升,此时手机操作、交互无卡顿感。
同时,我们实现了调用栈符号和信息的“一站式”匹配,实时解析后输出;并能够自动识别目标包名、进程,以便启动时即时跟踪,无需借助信号开启。
该工具的整体功能与malloc_debug的调用栈跟踪相近:
-
基于malloc/free函数簇的callee hook
-
调用栈运行时聚合,并以每个调用栈为单元进行统计:
-
输出内存信息:使用时长、申请次数、累计大小
-
输出按占用内存大小排序的调用栈TOP-K信息
-
输出单次大块内存申请的次数
-
支持native进程和Android runtime(APP进程)
-
自适应jemalloc和scudo
-
零成本接入,支持动态开启
另外,在该方案设计之初,我们就考虑到了研发、测试同学在三方应用稳定性以及内存比对等方面的需要,因此兼容并优化了针对三方APP、特别是头部应用厂商的支持,有相关业务需求的同学也可以尝试该工具。
2. 实现原理简述
基于malloc hook的用户态跟踪方案都大同小异:借助若干“查询表”,跟踪、记录、归并调用栈从而获取想要的信息;安卓malloc_debug、字节Raphael、微信Matrix和我们的Native Heap Insight亦是如此,他们实现细节的差异主要体现在具体业务和需求倾向上的取舍:易用性、集成度、告警机制等等,大体原理示意如下:
-
方案接入
https://about:blank/
setprop persist.track.malloc.enable track-heap setprop persist.track.malloc.program <process or package name[,others]> 注:Vendor进程有所不同,需要在上述属性中添加“vendor.”字样,两者互不冲突,例如: setprop persist.vendor.track.malloc.enable track-heap setprop persist.vendor.track.malloc.program vendor.qti.camera.provider-service_64 注:adb shell stop && adb shell start(MIUI 重启)或Native/Vendor进程重启后待其下次启动时生效 |
支持多个APP或进程同时开启、以“,”间隔,
例如在system server, system ui和语音助手上开启:
setprop persist.track.malloc.program system_server,com.android.systemui,com.miui.voiceassist
例如在三方APP“头条”、B站上开启:
setprop persist.track.malloc.program com.ss.android.article.news,tv.danmaku.bili
运行一段时间后,通过发送特定信号查看目标进程的内存使用情况:
https://about:blank/
pidof <process or package name> | xargs kill -51 |
信号触发后相关信息将以日志信息输出到logcat:
https://about:blank/
logcat | grep track-heap |
-
检视日志示例
4.1 调用栈信息
logcat "track-heap"日志会输出按调用栈占用内存大小、从高往低排序的Top-10,参考如下示例:
Note: 这里的调用栈信息、出于性能上的平衡,做了归并处理、只记录一份,即可能有其他的调用栈也符合类似的特征,但这里并未显示。
"sampled at ..."是将最近一次记录的调用栈显示在dump中:
-
可以尝试不断地dump以观测调用栈的更新情况 -- 调用栈的内容可能不变,但"sampled"的时间戳会被更新
-
如果该时间戳与当前dump时刻相距较远,则说明该调用栈近期未发生内存申请,可以结合自身业务、判断它是否是驻留型内存抑或存在泄漏的可能
4.2 PSS & malloc info.
PSS和malloc info.显示如下:
上述数值是在dump时直接获取,相较meminfo省去了中间的调用链路和临时的内存花销;同时,malloc info.减去了部分、在跟踪之前已被初始化的内存占用,更贴近业务启动后的实际占用情况。
4.3 内存统计释疑
“Native Heap”按照不同的“视角”可以划分如下三层:
-
从APP的角度,malloc/free函数簇即是上层调用的入口,用以创建和释放虚拟内存块;它体现的是业务实际关心的内存大小,这也是本方案内存统计的层面。
-
下一层是系统(libc)堆内存分配器,本质是一个虚拟内存管理者。除了向上给业务侧提供所需的内存资源(Allocated bytes),它自身的实现逻辑和数据结构也需要内存消耗,比如:
-
--> Spare space:业务侧分配过但当前已释放的空间,外碎片、预分配等也可划分在这里
-
--> Internal frag.:即内碎片,虽然单个字节数较小但巨大数量下也较为可观
-
--> System use: 分配器内部使用,如缓存、隔离区等
-
这一层面的统计可以简单地对应到meminfo “Native Heap”一行的后三个字段,或比对 4.2章节 所示的星号“*”标记的字段。
-
最后是操作系统层面、上层实际需要物理页面(含swap)的内存开销体现在这里。“Pages-to-GC”代表分配器已经确认无需使用、可以释放,但操作系统还未及时回收的空间。这层的统计可以从“Native Heap”一行的前五个字段相对应,也可参考 4.2章节 所示的PSS统计。
-
案例分享
K7BP systemui堆内存泄漏
内网统一认证 (Central Authentication Service)
本地复现,初始systemui meminfo:
https://about:blank/
rosemary:/ # dumpsys meminfo com.android.systemui Applications Memory Usage (in Kilobytes): Uptime: 1123027 Realtime: 1123027 ** MEMINFO in pid 16809 [com.android.systemui] ** Pss Private Private SwapPss Rss Heap Heap Heap Total Dirty Clean Dirty Total Size Alloc Free ------ ------ ------ ------ ------ ------ ------ ------ Native Heap 54050 52572 1472 31949 54768 104380 96590 7789 |
运行1小时左右,Native Heap增长到73MB:
https://about:blank/
** MEMINFO in pid 16809 [com.android.systemui] ** Pss Private Private SwapPss Rss Heap Heap Heap Total Dirty Clean Dirty Total Size Alloc Free ------ ------ ------ ------ ------ ------ ------ ------ Native Heap 73452 71868 1576 31227 74164 132088 120832 11255 |
此时触发信号打印检视日志如下:
可以看到createRenderInspector()申请的内存总大小排名第一:占用约26MB、累计申请1150次且还在持续增长。这样的申请行为并非业务模块预期,于是结合上述调用栈信息、确认该函数的调用入口:
再找到对应的资源释放的位置、将代码修改如下,内存不再增长,JIRA所述问题得到解决:
End of document