首頁 > 技術 > 正文

Android Perfetto 系列 14:heapprofd 与内存 Profiling

2026-10-30  ·  閱讀:159
  • 4096 bytes 是常用起点,适合大多数本地分析。
  • 怀疑大量小对象 native 分配时,可以降低间隔,但开销会上升。
  • 分配速率太高导致 buffer overrun 时,先增大 shared memory 或提高采样间隔。
  • 手写 HeapprofdConfig 必须显式设置非 0 的采样间隔;想接近精确可以设 1,但开销很高。0 是无效配置,不应作为“關閉采样”的写法。

报告里不要把采样结果写成“精确分配了 12.34MB”。更合适的写法是:“在 4096 bytes 采样间隔下,未释放分配主要集中在 A/B/C 三條调用栈,A 调用栈占比最高”。采样 profiler 的价值是找方向和排序,不是替代 allocator 账本。

小对象密集、样本少、窗口短、调用栈分散时,top stack 排名会不稳定。before/after 比较必须保持同一采样间隔、相近負载和同一方向窗口;不要比较 1% 或 2% 这类小差异,除非多次复现。报告里的 evidence_grade 可以按这个规则写:样本充足、连续 dump 走向一致、符号完整为 strong;命中 data loss、profile incomplete、unknown symbols、样本少或只复现一次为 weak。weak 时写“候选调用栈”,不要写“根因调用栈”。

Java heap dump 和 Java allocation sampling

这部分是对开头几张内存账的补充:heapprofd 能看 native malloc/new,也能在 Android 12 或更高版本上切到 Java allocation sampling,但它仍不替代 Java heap dump。

能力输出适合议题
heapprofd native profilingmalloc/new 调用栈谁分配了 native 内存
Java heap dump对象保留图谁持有 Java 对象
Java allocation samplingJava 创建对象的调用栈哪些代码制造了大量 Java allocation churn

Java allocation sampling 可以通过 heapprofd 配置 heaps: "com.android.art" 打开,也可以用脚本参数 --heaps com.android.art。它需要 Android 12 或更高版本。它记录对象创建时的调用栈,不记录对象什么时候被 GC,也不等价于 Java heap dump 的保留关系。

符号化和可信度

如果 flamegraph 里都是地址、unknown 或混淆后的 Java/Kotlin 名字,先处理符号化和反混淆。官方现在值得一试对采集到的 Trace 运行 trace_processor bundle 生成带符号信息的归档,再按符号化文档补 native symbols 和 ProGuard/R8 mapping。

报告里要记录 APK/build id、native symbols 版本、ProGuard/R8 mapping 版本;Build ID mismatch 时降級为地址级证据。第三方 SDK 或 stripped so 只剩地址时,下一步是补对应 build 的 unstripped symbols / mapping,而不是直接改业务代码。

读调用栈时也不要盲目过滤 libart.so、allocator glue 或操作系统库。ART 帧有时正是 Java 调 native、NativeAllocationRegistry 或对象创建路径的关键上下文。

先找 allocator/ART glue 之上的第一个 App、SDK 或业务帧;只有确认某类帧只是重复胶水层时再过滤。看到 DEDUPED、ICF 造成的函数折叠、Build ID mismatch、只有一帧等情况,要先按符号化议题处理。

unwind 可信度也要看:未知帧比例、单帧栈比例、Build ID 是否匹配、Java frame 是否可用、目标 ABI / Android 版本 known issues。缺符号会改变归因可信度;报告里要区分“已符号化可归因”和“只能定位到 so / allocator glue”。

报告里至少要交代清楚:

  • 方向進程是否 profileable/debuggable。
  • sampling_interval_bytes 和 continuous dump 间隔。
  • stats 里是否出现 heapprofd buffer overrun、client error、profile incomplete、heapprofd_unwind_time_us、heapprofd_client_spinlock_blocked、heapprofd_sampling_interval_adjusted 或 data loss。

出现 data loss 或 heapprofd buffer overrun 时,不要把数字写成精确账本。更合适的说法是“该调用栈是未释放分配的大头,采样條件如下”。

通用的 Trace 体检(buffer/ftrace 丢失)直接用第 12 篇那條 stats 查询;heapprofd 专用 health check 要单独跑。heapprofd_buffer_overran、heapprofd_client_error、heapprofd_hit_guardrail 等在 v57.2/v58.2 已存在,多数属于按需生成记录的 indexed stats;在没有 heap profile 的 Trace 上只查到两个 single 项,不能推断其他项是新版本专属。

先确认方向進程/heap 的 profile 或 dump 确实存在、窗口覆盖且已完成,再解释下面的异常查询。没有 profile 时应标记 profile_unavailable,不是“全部干净”;有 profile 但异常查询为空,也只能說明未记录到这些异常。heapprofd_unwind_time_us、heapprofd_client_spinlock_blocked、heapprofd_sampling_interval_adjusted 是开销/采样上下文,不应与非零 error/data_loss 一律判失败。

heapprofd_last_profile_timestamp 是辅助的最后 profile packet 時間,不能替代 heap_profile.ts_end、diamond 和最终完成狀態来证明方向窗口完整。下列查询保留这些上下文供复查:

本文由News整理發布,僅供參考。

12345678
評論載入中…

友情連結申請友鏈

聯盟矩陣53