应用内存拆解分析方法
来源:飞书 wiki(obj_token: YGCSdw8REo3HyQxdCA4chraPnXe)
附件已本地化:
attachments/YGCSdw8REo3HyQxdCA4chraPnXe/aggregate_showmap_gfxinfo.py(应用内存分类脚本)、gpu_mem.sh(跨芯片平台图形内存脚本)
应用内存拆解分类


📷 内嵌电子表格:sheet token
QrP4swQuvhxOLBtKEGLcdHqLnZb(sheet_idZoRSvc),建议在飞书中查看完整数据。
👉 应用内存分类脚本解析:
python aggregate_showmap_gfxinfo.py -s showmap.txt -g gfxinfo.txt(脚本见aggregate_showmap_gfxinfo.py)

👉 跨芯片平台获取图形内存脚本(需root权限):
adb shell sh /data/local/tmp/gpu_mem.sh <pkgname>(脚本见gpu_mem.sh)

分析方法
整机内存占用分解成:1)系统静态预留内存;2)内核占用内存;3)进程Pss内存;
排序Top差距项(按Pss)
**Pss内存:**应用进程按比例分摊的物理内存大小,它体现了应用在整机内存占用中的贡献。

差距项横向对比(按Rss)
**Rss内存:**应用进程实际访问到的物理内存大小,它体现了应用真实访问的数据量。

👉 相同项的Pss差距与Rss差距对比,若Pss差距>Rss差距,说明与其他进程shared内存更少,private内存占用更多,反之,情况相反。

Top差距项展开分析
Code(OAT、APK、VDEX、SO)
小米P1(SystemUI OAT)

荣耀Magic8pro(SystemUI OAT)

**Vss内存:**进程映射的虚拟内存大小,它体现了所映射文件的大小。
👉 文件大小对比:systemui业务代码文件大小(Vss),P1(164824)是Magic8pro(29668)的5.6倍,造成如此大差距的原因:P1上采用speed全编译模式,将所有java字节码编译成本地机器码;而Magic8pro采用speed-profile编译模式,将部分java热点类及方法编译成本地机器码。使用
adb shell pm art dump [packageName]确认应用编译模式。

👉 **文件访问量(Rss)对比:P1(100326)是Magic8pro(23868)的4.2倍,**造成如此大差距的原因:一是dex文件编译模式不同;二是systemui应用引入了dagger框架,它解决组件依赖复杂、降低耦合、提升可维可测性,但它会遍历依赖树,加载解析几乎所有代码。具体分析方法参考:文件页内存调试分析 @王辉

👉 优化思路: 1)应用dex文件采用speed-profile编译模式,覆盖应用高频典型场景的热点类和方法,文件大小减少79%(88360K ⇒ 18712K); 2)aod和plugin插件包,apk插件方式改成jar包等插件方式,跟随systemui主包一起speed-profile编译; 3)仅定制组件不引入dagger功能,以及dagger非核心组件采用懒加载方式,减少代码访问量。

NativeHeap
- native堆-通过工具分析内存占用 @兰春佳
- SystemUI匿名页native堆内存分析 v2 @王宇飞
JavaHeap(DalvikNormal)
- Systemui Java堆-Hprof对比分析 @王博博
- Systemui Java堆 GC 差异分析 @王博博
- SystemUI匿名页java堆内存分析 @王宇飞
Graphics(GL、EGL)
优化思路
1)修改应用申请内存方式,静态改动态,动态改懒加载;
2)应用dex2oat避免采用speed全编译模式,采用speed-profile模式编译热点类和函数,增强代码和数据的局部性;
3)应用接入OnTrimMemory,在系统内存紧张时,业务主动释放可重建的冷数据;
4)对应用仅使用一次或很少使用的apk,在使用完成后主动dontNeed告知内核回收;
5)应用业务在后台集中工作,避免随机运行,减少内存频繁换入换出量;
6)应用使用系统公共库,避免独自集成系统SDK已有能力,减少引入不必要的私有数据;
7)业务使用外部模块能力时,减少不必要的库依赖,确实需要时,使用动态链接方式,避免静态链接;
8)核心业务与辅助业务采用进程分离方式,根据产品内存规格配置进程常驻与否,根据系统内存压力,查杀辅助业务进程;
👉 内存降负载原则:在用户体验无明显下降的前提下,减少内存占用。