RSS 内存泄漏排障全攻略(下篇)
本原创文章帖发布在华为开发者联盟社区,欢迎开发者前往访问评论交流,更多与该内容相关讨论,请点击原帖查看:
运维态与开发态分析方法,从日志到代码行的"破案之路"
前言
在《RSS 内存泄漏排障全攻略(上篇)》中,我们已经搞懂了 RSS 内存泄漏的基本概念,学会了如何查看 RSS 内存、订阅故障事件,并掌握了 smaps、NMD、内存栈三类维测日志的规格与获取方法。这些内容为我们搭建了完整的"认知框架"和"工具箱"。
本篇将在此基础上,聚焦"如何用这些工具真正定位到泄漏根因"。我们将从运维态的 smaps 日志分析和内存栈日志分析方法讲起,借助二级根因速查表快速定界故障类型;再转到开发态,介绍如何使用 DevEco Studio、hidumper、hiprofiler 等工具在本地复现并定位问题;最后给出把 RSS 内存泄漏扼杀在摇篮里的实践建议。
建议结合上篇一起阅读,让"认知—感知—分析—定位"形成完整闭环。
六、运维态问题分析:从日志到根因的"破案之路"
6.1 smaps 日志分析方法
smaps 日志就像一份"内存账单",通过分析它,我们可以按照内存类别聚类并排序,找出占用最高的内存类型——这就是本次内存泄漏的二级根因。
具体步骤如下:
• 通过订阅资源泄漏事件,在沙箱中接收故障日志
/data/storage/el2/log/resourcelimit/RESOURCE_OVERLIMIT_XXXX_XXXX.log
• 在故障日志中搜索关键字 LOGGER_MEMCHECK_SAMPLIFY_SMAPS_INFO,读取数据
// log
// LOGGER_MEMCHECK_SAMPLIFY_SMAPS_INFO 日志示例
// Size:内存段大小 Rss:常驻内存 Swap:交换内存
// Category:内存类别 Counts:数量 Name:内存段名称
Size Rss Swap Category Counts Name
512 44 8 arkts-static heap 2 [anon:ArkTs Static Object Space]
256 180 44 arkts-static heap 1 [anon:ArkTs Static Non Movable Space]
1582104 112 0 AnonPage other 42 [anon]
1780224 1044 292 ark ts heap 34 [anon:ArkTS Heap]
512 12 4 ark ts heap 2 [anon:ArkTS Heapread only space]
3072 1424 1112 ark ts heap 12 [anon:ArkTS Heapnon movable space]
256 40 8 ark ts heap 1 [anon:ArkTS Heapshared non movable space]
256 44 4 ark ts heap 1 [anon:ArkTS Heapshared read only space]
40960 320 40160 ark ts heap 1 [anon:ArkTS Heapshared huge object space]
5888 5712 16 ark ts heap 23 [anon:ArkTS Heapappspawn space]
512 272 32 ark ts heap 2 [anon:ArkTS Heapshared old space]
768 36 340 ark ts heap 3 [anon:ArkTS Heapsemi space]
2560 1592 0 ark ts heap 10 [anon:ArkTS Heapshared appspawn space]
33554432 120 0 AnonPage other 5 [anon:partition_alloc]
128 32 4 FilePage other 4 /system/bin/appspawn
32 0 32 native heap 1 [anon:native_heap:meta]
2124 1796 8 .so 4 /system/lib/ld-musl-aarch64.so.1
2992 48 16 AnonPage other 1 [anon:ld-musl-aarch64.so.1.bss]
4 4 0 AnonPage other 1 [kshare]
16 16 0 AnonPage other 2 [shmm]
6288 3724 2520 native heap 108 [anon:native_heap:brk]
280 4 0 FilePage other 1 system/etc/zoneinfo/tzdata
47136 904 872 native heap 24 [anon:native_heap:jemalloc meta]
9186304 6041112 277404 native heap 9 [anon:native_heap:jemalloc]
......
分析技巧:按照 Category 列进行聚类,对每种类型的 Rss 列和 Swap 列求和,排序后找出内存总量占用最大的类型。
例如,经过排序发现 native heap 类型的内存总量最大:
// log
// native heap 类型内存总量最大
Size Rss Swap Category Counts Name
47136 904 872 native heap 24 [anon:native_heap:jemalloc meta]
9186304 6041112 277404 native heap 9 [anon:native_heap:jemalloc]
......
// 结论:此时发生的 RSS 内存泄漏的二级故障为NativeHeap堆过大
一旦确定了二级根因,就可以将内存栈日志导入 DevEco Studio,进一步定位到具体的泄漏代码行。

图 1:DevEco Studio 中 smaps 日志分析界面
6.2 内存栈日志分析方法
将内存栈日志导入 DevEco Studio 后,按以下步骤排查可疑内存泄漏点:
• 单击"导入文件"按钮导入内存栈日志
• 基于前置分析的二级根因选择不同的泳道:
• 如果二级故障为 NativeHeap 堆过大,选中 All Heap 泳道
• 如果二级故障为其他类型,选中 ALL Anonymous VM 泳道
• 单击 Call Trees 查看内存申请调用栈
• 选择 Created & Existing,筛选申请并且未释放的内存及其调用栈
• 找到内存申请异常的内存及其调用栈
• 结合调用栈对代码进行分析,找到泄漏根因

图 2:DevEco Studio 中内存栈日志分析界面
七、二级根因速查表:Category 对应什么故障?
通过分析 smaps 日志中的 Category 列,可以快速定位到二级故障根因。以下表格列出了常见的内存类别及其对应的故障类型和定位手段:
| 内存类别(Category) | 二级故障根因 | 定位手段 |
| native heap | NativeHeap 堆过大 | 参考 NativeHeap 堆过大导致内存泄漏故障模式说明 |
| ark ts heap | 匿名映射-动态 ArkTS 虚拟机堆内存较大 | 参考 ArkTS 内存泄漏故障模式概述 |
| AnonPage other | 其他匿名页映射大 | 参考匿名映射过大导致内存泄漏故障模式说明 |
| FilePage other(ashmem) | 匿名映射-Ashmem 过大 | 优先用 smaps 定界到二级根因 |
| jsvm heap | 匿名映射-龙雀 JSVM 虚拟机堆内存较大 | 优先用 smaps 定界到二级根因 |
| kotlin heap | 匿名映射-KMP Kotlin 堆内存较大 | 优先用 smaps 定界到二级根因 |
| dart heap | 匿名映射-Flutter 虚拟机堆内存较大 | 优先用 smaps 定界到二级根因 |
| rn-hermes heap | 匿名映射-RN 虚拟机堆内存较大 | 优先用 smaps 定界到二级根因 |
| arkweb-js heap | 匿名映射-ArkWeb V8 虚拟机堆内存较大 | 优先用 smaps 定界到二级根因 |
| arkts-static heap | 匿名映射-静态 ArkTS 虚拟机堆内存较大 | 优先用 smaps 定界到二级根因 |
| stack | 栈内存过大 | 优先用 smaps 定界到二级根因 |
| .so | 文件映射-共享库过大 | 优先用 smaps 定界到二级根因 |
| .ttf | 文件映射-字体文件过大 | 优先用 smaps 定界到二级根因 |
| .hap | 文件映射-HAP 包过大 | 优先用 smaps 定界到二级根因 |
| FilePage other | 文件映射-其他过大 | 优先用 smaps 定界到二级根因 |
| / | NativeHeap、ArkTS 虚拟机堆、文件映射等组合使用过大 | 优先用 smaps 定界到二级根因 |
(表 1:RSS 内存泄漏二级根因对照表)
八、开发态问题分析:在本地"重现案发现场"
对于在开发验证过程中遇到的 RSS 内存泄漏问题,或者运维态遇到的已知场景的泄漏问题,开发者可以在本地使用 DevEco Studio 的 Profiler 工具、hidumper 等开发工具对问题进行复现并抓取维测分析。
8.1 故障分析工具说明
hidumper:命令行维测利器
使用 hidumper --mem pid 获取指定进程的内存使用情况:
// bash
# hidumper --mem 9598
// 获取进程 9598 的内存使用情况
-----------------------------------------------[memory]----------------------------------------------
Pss Shared Shared Private Private Swap SwapPss Heap Heap Heap
Total Clean Dirty Clean Dirty Total Total Size Alloc Free
( kB ) ( kB ) ( kB ) ( kB ) ( kB ) ( kB ) ( kB ) ( kB ) ( kB ) ( kB )
-----------------------------------------------------------------------------------------------------
GL 0 0 0 0 0 0 0 0 0 0
Graph 0 0 0 0 0 0 0 0 0 0
ark ts heap 46325 6888 0 45804 0 88 2 0 0 0
arkts-static heap 4 0 0 4 0 416 15 0 0 0
guard 0 0 0 0 0 0 0 0 0 0
native heap 2382093 3528 0 2381572 0 31500 1365 68892 67285 3247
.hap 41744 0 0 41744 0 0 0 0 0 0
AnonPage other 1544 356 0 1500 0 6140 172 0 0 0
stack 420 0 0 420 0 0 0 0 0 0
.db 32 0 0 32 0 0 0 0 0 0
.so 9701 56360 3720 1020 1096 31772 905 0 0 0
dev 17 0 384 16 0 0 0 0 0 0
.ttf 436 1564 0 12 0 0 0 0 0 0
arkweb-pa heap 0 0 0 0 0 120 4 0 0 0
FilePage other 314 2332 8 0 12 4284 169 0 0 0
-----------------------------------------------------------------------------------------------------
使用 hidumper --mem-smaps pid 获取指定进程的详细内存使用情况(会累加相同内存段的内存值):
// bash
# hidumper --mem-smaps 9598
// 获取进程 9598 的详细 smaps 内存信息
--------------------------------[memory]---------------------------------
Shared Shared Private Private
Size Rss Pss Clean Dirty Clean Dirty Swap SwapPss Counts
hiprofiler:堆内存分配调用栈抓栈工具
当定界到 native heap、AnonPage other、FilePage other、Ashmem 等类型内存发生泄漏时,可以使用 hiprofiler 对进程的堆内存分配操作抓栈,分析泄漏点。
DevEco Profiler 调优工具
通过 DevEco Studio 中 Profiler 工具的 Allocation 功能,可以对应用进程的内存申请趋势以及内存申请调用栈进行分析,定位出具体泄漏点。
8.2 故障分析方法
在 DevEco Studio 中调试时遇到应用闪退,可以按以下步骤排查:
• 在 DevEco Studio 中找到日志组件,选择"应用终止",筛选调试应用的历史退出原因
• 如果原因为 RssThresholdKiller,说明应用发生了 RSS 内存泄漏故障

图 3:DevEco Studio 日志组件中查看应用终止原因
• 确认问题为 RSS 内存泄漏后,使用 Profiler 工具的 Allocation 功能进行分析
• 如果发现应用内存占用超出预期,可以初步断定存在内存泄漏问题

图 4:DevEco Studio Allocation 分析界面
• 展开 Memory 泳道,观察 Native Heap、AnonPage Other、Dev、Guard、.so、.ttf、Stack 等泳道的增长情况,初步定界为 RSS 内存泄漏问题,并精确到二级根因

图 5:DevEco Studio Memory 泳道分析界面
• 最后根据二级根因,结合内存栈日志分析方法定位内存泄漏点
九、结论与建议:把RSS内存泄漏扼杀在摇篮里
RSS内存泄漏不是玄学,而是一门可以通过系统方法排查的技术活。总结一下本文的核心要点:
1. 建立内存监控意识:不要等系统来“请”你的应用。通过订阅资源泄漏事件和应用终止事件,提前感知内存异常,做到早发现、早处理
2. 掌握日志分析能力:smaps日志帮你找到内存泄漏的“大类”,NMD日志帮你定位到具体内存块,内存栈日志帮你追溯到代码行。三者配合,形成完整的排查闭环。
3. 善用开发工具:DevEco Studio的Profiler Allocation功能、hidumper命令行工具、hiprofiler抓栈工具,是排查内存泄漏的三大利器。开发态多花10分钟排查,运维态就能少花10小时救火。
4. 关注低端设备:低端设备内存总量小,更容易触发低内存状态。如果你的应用面向低端设备,内存优化不是“锦上添花”,而是“生死攸关”。
最好的内存优化,是在写第一行代码时就考虑到内存管理。但即使代码已经写完了,掌握正确的排查方法,也能让问题迎刃而解。
🔗 官网开发者学堂视频:华为开发者学堂

🔗 社区DFX专题文章: 华为开发者问答 | 华为开发者联盟


【扫码加入 HarmonyOS DFX 技术交流群】
更多推荐


所有评论(0)