内存分析工具使用手册
内存日志抓取参考
📌 可以搭配memory-baseline skill一起使用 https://git.n.xiaomi.com/performance-analysis/perf-analysis/-/blob/main/skills/memory-baseline/SKILL.md?ref_type=heads
Smaps
adb root
拿到systemui的进程号
adb shell 'cat /proc/$(pidof com.android.systemui)/smaps' > systemui_smaps.txt
adb shell pm art dump com.android.systemui > systemui_dex.txt
adb shell dumpsys meminfo com.android.systemui > systemui_meminfo.txt
adb shell dumpsys gfxinfo com.android.systemui > systemui_gfxinfo.txt通过 https://github.com/Gracker/Android-App-Memory-Analysis 提供的脚本拆分 smaps文件:
python3 smaps_parser.py -f smaps >smaps_parser.txt
python3 smaps_parser.py -f ./data/smaps3 > ./data/smaps_parser3.txt
showmap
adb shell 'showmap $(pidof com.android.systemui)' > before-O11U-showmap.txtHprof
抓取hprof
adb shell 'am dumpheap `pidof com.android.systemui`'
# `pidof com.android.systemui`替换为对应的进程号使用platform-tools中的工具转换后在MAT比较对象个数,比较直观可以看出差异
./hprof-conv hprofData/bg_com.android.systemui-3.hprof hprofData/bg_standard_3.hprof

Mat 无法打开standard hprof的问题:
python3.10 hprof_fix_0x1c.py --input P1-aging-standard.hprofNative Heap Insight的使用
参考文档:堆内存检视方案(Native Heap Insight)
- 需要userroot或者userdebug的包;
- 通过如下命令,之后便可使用Native Heap Insight:
adb root
adb remount
adb shell setprop persist.track.malloc.enable track-heap
adb shell setprop persist.track.malloc.program com.android.systemui
adb shell stop
adb shell start- 对需要测试的场景进行操作,操作一段时间结束后通过如下命令获取相关日志:
adb shell ps -A | grep systemui # 获取systemui的pid
adb shell kill -51 <pid> # pid为上一步中获取到的systemui的pid
adb logcat | grep track-heap >native_heap_insight.txt
# 或者:
adb shell 'kill -51 $(pidof com.android.systemui)'- 查看日志,该日志将Native排名前十的堆栈进行打印,通过查看堆栈发现Native异常分配内存的情况;
heap_profile 抓取
参考文档:Perfetto heapprofd 原理解析 — Native Heap vs ART Heap
1. Native heap sampling
使用下面命令开始抓取trace文件
heap_profile -c 间隔时间 -n 包名
例如每100ms抓取一次systemui的内存: ./heap_profile -c 100 -n com.android.systemui

可以进一步拆解定位
如果遇到抓取的trace为空的情况,可以将 SELinux 设置为宽容模式(Permissive Mode),排除权限问题
adb shell setenforce 0
adb shell getenforce如果还是抓不到,可以试试:
具有已启用 profileable 清单配置的发布 build 变体的应用,也称为可分析应用。默认情况下,应用将此配置设置为 true。如需检查或更改此配置,请打开应用的清单或 AndroidManifest.xml 文件,然后在 <application> 部分中查找 profileable 清单配置:
<profileable android:shell="true" />最终方法:
如果上述方法验证后还是抓不到数据,打个userdebug的rom就可以抓到,本地没有失败过
2. Java heap sampling
Java heap sampling抓取的是创建对象堆栈的采样(采样大小默认是4KB)
https://perfetto.dev/docs/data-sources/native-heap-profiler#java-heap-sampling
./heap_profile --name com.android.systemui --heaps com.android.art --continuous-dump 1000
3. Java heap dump
主要解决内存泄漏问题
Java heap dump抓取的是当前Java heap的快照,不包括堆栈信息,slice堆叠表现为对象间引用关系,注意和Java heap sampling区分
https://perfetto.dev/docs/data-sources/java-heap-profiler
tools/java_heap_dump -n com.android.systemui --output ./data/
native+trace
高通平台获取native heap
KBA-220524233716 — 待本地验证可行性
# 请参考如下方式获取com.android.systemui的 native heap
adb root
adb shell "setenforce 0"
adb shell "chmod 777 /data/local/tmp"
adb shell "setprop libc.debug.malloc.program app_process64"
adb shell "setprop libc.debug.malloc.options \"backtrace leak_track\""
adb shell "stop"
adb shell "start"
# 复现问题
adb shell "kill -47 $(pidof com.android.systemui)"
adb shell "logcat -b all |grep -E \"malloc_debug\""
# 输出示例:
# 02-20 05:43:49.088 10021 10073 E malloc_debug: Dumping to file: /data/local/tmp/backtrace_heap.10021.txt
adb pull /data/local/tmp/
# 或者:
adb shell am dumpheap -n $(pidof com.android.systemui) /data/local/tmp/systemuinativeheap.txt
adb pull /data/local/tmp/火焰图抓取分析
参考文档:ubuntu快速抓取火焰图
1. 生成perf.data
# 进入个人电脑的simpleperf目录下一般都在Android/Sdk下
./app_profiler.py -p com.android.systemui -r "-e task-clock:u -f 1000 -g"
# 抓应用 用 -p {包名}
./app_profiler.py -p com.android.systemui -r "-e task-clock:u -f 1000 -g"
# 遇到抓不了的情况,尝试以下命令:
adb shell setenforce 0
adb shell getenforce
# 抓sf 用 --pid {进程号}
adb shell ps -ef | grep -Ei "surfaceflinger"
# 得到Surfaceflinger的进程号为1140
./app_profiler.py --pid 1140 -r "-e task-clock:u -f 100 -g"2. 转成report.html
./report_html.py3. 转成Gecko Profile格式
./gecko_profile_generator.py -i perf.data | gzip > gecko-profile.json.gz可以用 https://profiler.firefox.com/ 打开
依靠设备本身抓取simpleperf:
chrt -f 10 simpleperf record -g --app com.android.systemui --duration 300 -e filemap:mm_filemap_add_to_page_cache -c 1 -m 65536 --cpu-percent 99 --user-buffer-size 1536M -o /data/local/tmp/filemap.perf.data
# 解析:
python3 report_html.py -i filemap.perf.data -o flamegraph.html火焰图+trace
参考文档:perf2perfetto工具使用说明
export ANDROID_HOME=/home/mi/Android/Sdk/
export ANDROID_SDK_ROOT=/home/mi/Android/Sdk/
export ANDROID_NDK_HOME=$ANDROID_SDK_ROOT/ndk/26.1.10909125
python3 run.py --pid 4764 --tid 4764,5200 --duration 20产物是merged_trace.perfetto-trace
方便看到调用堆栈,不需要修改代码

filemap拆解
可以直接使用
一键抓取生成报告,并且可以使用ai拓展功能

参考文档:
- Filemap 文件页堆栈抓取
- 文件页内存调试分析 — 里面有文件页释放相关介绍,但是无法抓取详细原因,只能看释放量
adb push filemap_catch /data/local/tmp
adb shell
cd /data/local/tmp/
chmod +x filemap_catch
./filemap_catch -p com.android.systemui -s -d
# 不重启进程:push的文件是filemap_catch_v2
./filemap_catch_v2 -p com.android.systemui -q -d -t 300
# 将产物push出来后解析
adb pull /data/local/tmp/filemap.perf.data
adb pull /data/local/tmp/filemap_inode.json
./simpleperf_report_u22 -i filemap.perf.data -o filemap_all.html --inode_file filemap_inode.json
# 解析单个文件页:
./simpleperf_report_u22 -i filemap.perf.data -o filemap_P11U_V2_266338315_15890304.html --dev_inode 266338315_15890304
inode通过 filemap查询
Mem_profile
参考文档:Franklin1 Android Memtrack
mem_profile是用于mali平台获取GPU相关内存信息,所以cat这个信息主要用于分析Mtk/Xring平台的GL mtrack内存信息,如果需要更进阶的分析graphics的方法,可以参考这篇文档 Graphics内存数据拆解
Mtk平台直接执行如下命令
adb shell 'cat /sys/kernel/debug/mali0/ctx/$(pidof com.android.systemui)_*/mem_profile'Xring平台,需要:
如果出现/sys/kernel/debug下无内容得情况,则需要先执行:
adb shell mount -t debugfs none /sys/kernel/debugcat mem_profile之前需要先执行如下命令:
adb shell setprop vendor.mali.xfeature_mem_usage_report 1
adb shell stop
adb shell start通过mem_profile可以获取GFX Device Memory CPU Uncached、Vulkan Bound Buffer Memory、Vulkan Bound Image Memory通道相关的GPU内存信息,这些内存主要通过vkAllocateMemory api申请。