Systemui Java堆-Hprof对比分析

Showmap统计java堆,gc之后,P1 44M/magic 25M,相差约19M

[附件: ZNDabXMnworWBCx28FdctEp7nKc]

Hprof统计到的堆内存,P1 57.6M/magic 49.3M,相差约8.3M

虽然数据无法对上,但是java堆总体趋势P1确实差于magic,目前建议通过hprof分析

[附件: JrBcb94zzo2oftxjMKbcLQK9nih]

[附件: K5JabeTBfoa0PUxeLqrcGnGMnoe]

👀 为什么 HPROF(57.6M)> showmap(44M)? showmap中统计规则有问题,后续会和meminfo中的java heap大致保持一致 最终使用hprof分析,业务侧可以以hprof展示的堆内存占用为准

对比分析P1和magic的Hprof,并附上详细步骤

预置条件:

使用自动化工具(推荐):

  • 安装JDK,配置环境变量:MAT要依赖java环境
  • 安装HprofMatOpener-Installer-Bundled:

[附件: X7PybO0KbolRshxLEZuc8ncAn2b]

  • 具体使用可查看:

[附件: ScTSbauZOoyWTOx7Q49cCabZnWn]

  • 安装完成之后,双击任何从手机中pull出的hprof即可在mat中打开,无需环境依赖和格式转换

PS:之前的hprof_manager.exe存在一些信息丢失的问题,会造成hprof文件较小,请使用上述最新版本

或者手动一步步安装环境依赖:

  • 安装MAT:

[附件: CZ2xbuG1Foz4PMx0uZscrNgMnec]

  • 安装JDK
  • adb抓取hprof:
adb shell am dumpheap 包名/PID(建议使用pid) /data/local/tmp/test.hprof
  • 格式转换:

[附件: CrX2bHe5eoBlvXxiSvCcyByPn6f]

hprof-conv.exe 是 Android SDK 自带的工具,作用是将 Android 设备上生成的原始 hprof 文件转换为标准 JVM 格式

hprof-conv.exe test.hprof test.hprof

对比分析步骤:

1.同时打开两个hprof文件:

2.打开Histogram(堆直方图)

在 MAT 中,Histogram(堆直方图) 是最基础且常用的内存分析工具之一,它会按照类名对堆中所有对象进行分组统计,直观展示每个类的对象数量、内存占用情况

定位大对象 / 高频对象:找出占用内存最多、对象数量最多的类,缩小问题范围。

补充说明

[嵌入表格]

和 Dominator Tree(支配树)的区别:Histogram 是 “类” 维度的统计,而 Dominator Tree 是 “单个对象” 维度的统计。

  • 如果你想知道 “哪个类的对象整体占用内存最多”,用 Histogram;
  • 如果你想知道 “哪个具体对象占用内存最多”,用 Dominator Tree

3.结合 Compare Tables 功能,对比两个快照的 Histogram,发现类的对象 / 内存变化,定位差别对象

分别将两个hprof的Histogram添加到Compare Basket

点击”红色叹号”,生成Compared Tables

为了方便对比,可以导出到csv进行diff排序,选取top差异的类对象进行分析:

4.Mat继续定位类对象引用链,进而定位业务侧具体逻辑

以com.android.systemui.statusbar.StatusBarIconView此类对象为例

P1 上存在大量额外的 StatusBarIconView 对象,比对比机多170个StatusBarIconView对象

进一步分析:

Merge Shortest Paths to GC Roots:把所有 StatusBarIconView 实例到 GC 根引用的最短路径合并,找出它们的共同根引用,快速定位这一类对象的统一持有者。

exclude all phantom/weak/soft etc. references:排除虚引用、弱引用、软引用等引用类型,只保留强引用,这样能精准定位那些真正导致对象无法被回收的根引用。

测试机 244 个 StatusBarIconView 实例,最终被 9 个不同的根引用持有

对比机 74 个StatusBarIconView 实例,最终被 2 个不同的根引用持有

进一步展开上述第一个结果:展示了 StatusBarIconView 到根引用(ContentObserver$Transport)的最短路径,以及路径上的关键节点(如 CollapsedStatusBarFragment、MuiStatusIconContainer

对于这种批量分析差异的情况,比较适合最短路径的根引用,进一步展开:即可看到37个StatusBarIconView 详细信息和地址

5.竞品机magic同样的操作展开相关引用链,即可定位到差异根源

👀 最终结论: 与业务讨论,多状态栏/怀疑对比机相关图标进行了懒加载(lazy mode),导致状态栏/下拉通知栏的图标数量/堆内存差异,后续业务模块会进一步给出修改方案

另外一个分析案例可以查看:Systemui hprof分析实操