内存工具-无标签匿名页溯源

来源飞书文档 | 有问题可联系 @钟万勇 解决

⚠️ 图片说明:本篇 5 张图片因飞书 MCP 下载返回 403(无权限),均未能上传图床。已用飞书返回的图片描述文字替代,原始链接见每张图下方的注释,需手动补图。

解决的问题说明

业务在内存分析过程会遇到一些无标签的匿名页无法进一步拆解,会有几种具体表现为:

  • 一些内存统计脚本表现为”匿名页其他”比较大
  • showmap中汇总的anon很大
  • 进一步表现为showmap -v中某个anon的条目占比比较大
  • 再进一步可追溯到smaps中某个地址区间占用的内存大,但没有具体的标签,业务不知道这块内存的作用
➜  CatchMemDataShell git:(v1) ✗ adb shell showmap 18393  |  grep "\[anon\]" -iE | sort -k 2 -r
 4090436    11836    11836        0        0        0    11836        0        0     10240         0         0        0        0        0 1150 [anon]
➜  CatchMemDataShell git:(v1) ✗ adb shell showmap 18393 -v  |  grep "\[anon\]" -iE | sort -k 2 -r | head -10
   11472    11472    11472        0        0        0    11472        0        0     10240         0         0        0        0        0   rw- [anon]
     320      320      320        0        0        0      320        0        0         0         0         0        0        0        0   r-- [anon]
     256        4        4        0        0        0        4        0        0         0         0         0        0        0        0   rw- [anon]
     128        4        4        0        0        0        4        0        0         0         0         0        0        0        0   rw- [anon]
      36        4        4        0        0        0        4        0        0         0         0         0        0        0        0   rw- [anon]
       4        4        4        0        0        0        4        0        0         0         0         0        0        0        0   rw- [anon]
       4        4        4        0        0        0        4        0        0         0         0         0        0        0        0   rw- [anon]
       4        4        4        0        0        0        4        0        0         0         0         0        0        0        0   rw- [anon]
       4        4        4        0        0        0        4        0        0         0         0         0        0        0        0   rw- [anon]
       4        4        4        0        0        0        4        0        0         0         0         0        0        0        0   rw- [anon]
......
 
acfc8000-aefc8000 r-xs 02000000 00:01 2922                               [anon_shmem:dalvik-jit-code-cache]
Size:              32768 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Rss:                   0 kB
Pss:                   0 kB
......
THPeligible:           0
VmFlags: rd ex sh mr mw me ms
aefc8000-afafc000 rw-p 00000000 00:00 0
Size:              11472 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Rss:               11472 kB
Pss:               11472 kB
Pss_Dirty:         11472 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:     11472 kB
Referenced:        11472 kB
Anonymous:         11472 kB
KSM:                   0 kB
LazyFree:              0 kB
AnonHugePages:     10240 kB
ShmemPmdMapped:        0 kB
FilePmdMapped:         0 kB
Shared_Hugetlb:        0 kB
Private_Hugetlb:       0 kB
Swap:                  0 kB
SwapPss:               0 kB
Locked:                0 kB
THPeligible:           1
VmFlags: rd wr mr mw me ac
ebad6000-ebad7000 ---p 00000000 00:00 0                                  [anon:dalvik-Sentinel fault page]
Size:                  4 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Rss:                   0 kB
Pss:                   0 kB
......

此页面介绍的工具主要帮助解决此类问题,具体效果为:会将所有smaps中没有标签的区间对应申请的调用栈打印出来,来辅助业务定位这块无标签内存区间的来源和作用,进一步做内存的优化。

📷 图片描述:内存工具中无标签匿名页溯源的示例结果。红色框内是内存地址区间 “e4d54000 - e5c58000”,其 Size 为 11728 字节,Res、Swap、SwapSize 均为 11728 字节,0x0000000000000000 处的调用栈信息被突出显示。

采集工具使用指导

完整使用指导详见:典型场景工具使用指导

工具获取

工具下载地址(采集工具 catch_mem): 已转存自有文件床,见文末「附录:工具下载」与 附件下载索引.md(网盘原链 kpan.mioffice.cn 密码 869f 作备份)。

下载最新的 catch_mem 工具。

采集命令说明

🍰 注意:采集命令中 -e 参数指定 mmap。 冷启动场景的命令格式:

//linux ./start appdump --package_name <进程名> -b <event buf> -B <stack buf> -a <mem_use buf> -e <采集类型> -c --scenario <场景名> -s <设备序列号> -d <device name>

//windows .\start.exe appdump --package_name <进程名> -b <event buf> -B <stack buf> -a <mem_use buf> -e <采集类型> -c --scenario <场景名> -s <设备序列号> -d <device name>

例如:在 O2S 设备上采集浏览器场景的 mmap 内存日志的命令:

.\start.exe appdump -b 256 -B 256 -a 512 -c -e mmap -s 078AC89243448540 --scenario browser --package_name com.android.browser -d o2s

采集日志内容

采集完成后的内存日志目录结构如下:

📷 图片描述:内存工具采集完成后的内存日志目录结构。目录名为 “browser_traces_o2s”,包含多个文件夹,如 gfs_data、hprof、log_data 等,其中 “mem_use_data” 和 “memuse_filename_data” 文件夹的修改日期为 2026/2/10 14:29,“showmap_data” 文件夹为 14:30,“simpleperf_data” 为 14:24,“stack1_data” 和 “stack2_data” 为 14:30,“symbol_data” 为 14:32,“traces” 为 14:31。

<!--https://minio.898311.xyz/blogimg/1782793061500_161164.png -->

导出测试场景符号库

符号导出工具和日志采集工具在同目录,工具名称为 collect_libs.exe

//获取应用的进程名
adb shell ps -ef | grep 进程名
 
//进程号为要采集进程的进程号
//linux
./collect_libs --pid <进程号> --pull <symbol输出目录>
//windows
.\collect_libs.exe --pid <进程号> --pull <symbol输出目录>

将导出的符号库文件放到内存日志采集目录中的 symbol_data 目录(目录不存在时手动创建,要确保目录名称必须为 symbol_data)中。

📷 图片描述:内存日志采集完成后目录结构中的 symbol_data 文件夹内容。文件夹内包含多个文件夹,如 apex、appdump、data、product、system、system_ext、vendor 等,均为 2026 年 2 月 10 日 14:32 创建。

解析工具使用指导

工具下载地址(解析工具 smaps_memory_data_process): 已转存自有文件床 → smaps_memory_data_process (303M)(更多见 附件下载索引.md)。

📷 图片描述:内存工具目录结构中的 smap_process 文件夹内容。

🌰 注意:工具为网盘 smap_process 目录中的 smaps_memory_data_process 可执行文件,该工具只能放置在 Linux 环境上使用。

目录结构要求

确保如下所示的必要日志文件目录已经存在:

设备目录/
├── mem_use_data/          # 存放后缀为 .use.data 的二进制文件
├── stack1_data/           # 存放后缀为 .stack1.data 的二进制文件
├── stack2_data/           # 存放后缀为 .stack2.data 的二进制文件
├── memuse_filename_data/  # 存放后缀为 .filename.data 的二进制文件
├── showmap_data/          # 存放后缀为 .end.smap 的 Smaps 文件
└── symbol_data/           # 存放符号库文件

解析工具的命令行参数说明

参数说明必填
--input_nums输入目录的个数
--input_dirs输入目录列表(多个目录用空格分隔)
--output_dir输出结果目录

使用示例

处理单个设备的内存日志

smaps_memory_data_process \
  --input_nums 1 \
  --input_dirs /path/to/device1 \
  --output_dir /path/to/output

例如解析上述采集到的 browser_traces_o2s 目录中的日志时,使用如下命令:

./smaps_memory_data_process --input_nums 1 --input_dirs ~/browser_traces_o2s --output_dir ~/output

执行完成后的输出文件都放置在 ~/output 目录中。

处理多个设备的内存日志

smaps_memory_data_process \
  --input_nums 3 \
  --input_dirs /path/to/device1 /path/to/device2 /path/to/device3 \
  --output_dir /path/to/output

输出文件

解析工具运行完成后会在指定的输出目录中生成以下文件:

文件类型文件名格式说明
合并文件{设备名}_{基础名}_merged.txt合并后的内存日志
符号化文件{设备名}_{基础名}_merged.symbolized.txt符号化后的内存日志
CSV 报告{设备名}_{文件名}.csvSmaps 解析结果

最终需要关注的结果文件为 CSV 报告文件,文件中会详细的展示每个匿名内存的映射区间,以及该映射发生时的调用栈轨迹信息(不关注的列信息可以隐藏)。

📷 图片描述:内存解析工具生成的 CSV 报告文件内容。报告中记录了多个匿名内存的映射区间(如 0x645000 - 0x6c58000 等),以及对应的调用栈轨迹信息。每行数据包含设备名、基础名、内存地址、大小、起始地址、结束地址、Swap、SwapSize、Res、Pos、SwapPos 等字段。

常见错误处理

错误信息原因解决方法
子目录不存在: mem_use_data缺少必要的子目录确保包含所有必需的子目录
缺少文件: ...缺少必需的数据文件检查各子目录中是否存在对应后缀的文件
输入目录数量不匹配input_nums 与实际输入目录数量不一致确保 input_nums 值与 input_dirs 数量一致
符号目录不存在: ...symbol_data 目录不存在在输入目录中创建 symbol_data 目录并放入符号文件

注意事项

  1. 文件命名 - 输出文件会使用输入目录名称作为前缀,请确保输入目录名具有可识别性
  2. 目录权限 - 确保对输入目录和输出目录都有读写权限
  3. 符号文件 - symbol_data 目录中需要包含完整的符号库文件
  4. 处理时间 - 大文件处理可能需要较长时间,请耐心等待

附录:工具下载(已转存自有文件床)

网盘 kpan.mioffice.cn(密码 869f)里的工具已全部镜像到自有文件床,可直接下载。完整清单(66 文件 / 全版本 / 全平台)见 附件下载索引.md。本篇核心工具直链:

工具大小下载
smaps_memory_data_process(本文档解析工具)303M下载
start.exe(采集,最新版 catch_1_0_4 / Windows)79M下载
collect_libs.exe(symbol,catch_1_0_4 / Windows)9M下载
start(采集,catch_1_0_4 / Linux ubuntu24)51M下载
collect_libs(symbol,catch_1_0_4 / Linux ubuntu24)7M下载

📦 全部 66 文件(catch_1_0_0 ~ 1_0_4 全版本、Windows/Linux、解析工具等):见 附件下载索引.md 🔗 网盘原链(备份,含未镜像的依赖库/旧版本完整包):https://kpan.mioffice.cn/webfolder/ext/H507l6zdDJX$uVm31GQvyw@@ | 密码 869f