内存分析工具使用手册

内存日志抓取参考

📌 可以搭配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.txt

Hprof

参考文档:Systemui Java堆-Hprof对比分析

抓取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.hprof

Native Heap Insight的使用

参考文档:堆内存检视方案(Native Heap Insight)

  1. 需要userroot或者userdebug的包;
  2. 通过如下命令,之后便可使用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
  1. 对需要测试的场景进行操作,操作一段时间结束后通过如下命令获取相关日志:
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)'
  1. 查看日志,该日志将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

参考文档:Perfetto系列-定制化内存分析插件使用说明

高通平台获取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.py

3. 转成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拆解

可以直接使用

https://git.n.xiaomi.com/performance-analysis/perf-analysis/-/tree/main/scripts/filemapTool?ref_type=heads

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

参考文档:

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/debug

cat 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申请。