首页 > 技术 > 正文

Android Perfetto 系列 14:heapprofd 与内存 Profiling

2026-10-30  ·  阅读:168

反过来也一样:heapprofd 里某条调用栈累计分配很高,不代表进程 RSS 会同幅度上涨。它可能是分配 churn:频繁申请、很快释放,Total malloc size 高,但 Unreleased malloc size 不高。内存难题要先分清“占住不放”和“反复制造临时对象”。

怀疑 mmap/native heap 之外的大块分配时,改查 smaps 的 Private_Dirty/Rss/Pss、maps 区间、Android 14+ syscall sys_mmap/sys_munmap/sys_madvise,或者 perf/simpleperf 的 mmap syscall callstack。heapprofd 只用于确认 malloc wrapper 是否也在贡献。

从 native 分配采样到调用栈

原理示意:heapprofd 采样 native 分配并记录调用栈;Heap Profile 不是 RSS 账本。

什么时候用 heapprofd

Java heap dump 看不到上升来源时,先看提升落在哪张账。只有 native heap 或 native wrapper 明显可疑时,再进入 heapprofd。

heapprofd 适合这些难题:

  • Native Heap / malloc wrapper 持续上涨,但 Java heap dump 看不出明显对象保留。
  • Bitmap、Skia、播放器 buffer、JNI/C++ 模块怀疑有 libc malloc/new 路径上的 native backing 占用。
  • C++ 模块、native service、daemon 的 malloc/new 异常。
  • 想知道某次业务操作后未释放分配是否增加。
  • 想把内存提升和线程运行、Binder、业务 Track Event 关联起来。

这些问题不该优先用 heapprofd:

  • 只想看 Java 对象引用关系。用 Java heap dump。
  • 想把每一次小分配都精确记成账本。heapprofd 默认是采样 profiler。
  • 目的 App 在 user build 上没有 debuggable 或 profileable。这类进程通常不能被 shell profile。
  • GraphicBuffer、dma-buf、GPU driver memory、Surface buffer 数目上涨。先走 meminfo Graphics/GL、dmabuf、GPU/graphics、SurfaceFlinger 的证据链,heapprofd 只用来排除或定位 malloc/new 包装层。

目标资格也要分开看。user build 主要面向 debuggable/profileable Java apps;userdebug/eng 可抓大多数 App 和 system services,但少量 critical services 可能被 SELinux never_profile_heap 之类策略禁止。system process 不靠 解锁。

快速抓一份 native heap profile

官方更推荐先用 tools/heap_profile 脚本。它会处理很多设备侧细节,适合单进程快速定位。

这条命令按进程名抓 15 秒,采样间隔 4096 bytes,每 5 秒产生一个 continuous dump:

1
2
3
4
5
6
7
out_dir=$(mktemp -d /tmp/heapprofd-com-example-app.XXXXXX)
tools/heap_profile android \
-n com.example.app \
-d 15000 \
-i 4096 \
-c 5000 \
-o "$out_dir"

脚本要求 -o 指向已存在且为空的目录;上面的 mktemp -d 为本次抓取创建独立空目录。输出目录里会有 raw-trace 和转换后的 profile 文件。把 raw-trace 拖到 Perfetto UI,就能看到 Heap Profile diamond。

按进程名抓和按 PID 抓差别很大。-n com.example.app 会命中已经运行的同名进程,也会等待后续启动的新进程;目标从 zygote specialize 到 App 进程时,heapprofd 可以尽早接上。多进程 App 要分别写多个 -n / process_cmdline,例如 com.example.app、com.example.app:remote、com.example.app:player;否则 remote/native 子进程的 malloc 不会进入 profile。按 PID 抓更适合已经稳定运行的现场,但会错过启动早期分配。官方也提醒,哪怕按进程名抓,zygote specialize 最早的一小段分配仍可能没记到。

如果要在 user build 上用 adb / shell 抓 App,需要 manifest 里允许 shell profiling:

1
2
3



这条路径只解决本地 shell profiling 权限,不等于线上可以远程抓任意使用者进程。

Android 15(API 35)起,App 可以通过 ProfilingManager 请求 heap profile。Android 17 又增加 OOM、异常等平台触发器,支持在相应事件发生时记录与请求 App 相关的分析结果;App 不在运行时,回调可能等到下次启动并注册监听器后才交付。结果受脱敏、权限和系统限流约束,不保证每次请求都能满足。线上方案要把它和 adb/profileable 的实验室路径分开造型。

和平台 Trace 合在一起抓

脚本适合快速定位,手写 TraceConfig 适合把 heapprofd 和平台数据源合并。先看最小 heapprofd 配置:android.heapprofd、process_cmdline、采样间隔、continuous dump、shared memory 和阻塞策略。

系统上下文是增强项:process_stats 看 RSS/PSS 风向,sys_stats 看系统内存压力,ftrace 关联线程和时刻窗,track_event 关联业务动作。allocation-heavy 场景里,heapprofd + ftrace 会互相增加扰动;heap+system-context preset 只适合短窗口实验室复现,并且要记录 ftrace/heapprofd stats、目标场景耗时是否被 profiler 改变。

本文由News整理发布,仅供参考。

12345678
评论加载中…

友情链接申请友链

联盟矩阵53