优化 so 大小能否减少 Android 应用的内存?从原理上讲是可以的,实际效果如何?一起来看看吧。
(本文待完善)
相关文章:
- Flutter split-debug-info 用法介绍 - 使用 split-debug-info 可以优化 Flutter libapp.so 大小
- Flutter App 内存测试 - 在若干简单场景下测试 Flutter 应用内存,为内存优化提供指导
背景
我们知道,Android 应用占用的内存有一类是 Code
。dumpsys meminfo
命令的输出中可以看到 Code 类别的内存:
关于 Code 内存,官网是这样解释的:
Memory that your app uses for code and resources, such as dex bytecode, optimized or compiled dex code, .so libraries, and fonts 来源
简单计算一下,发现 Code 内存大致包括 .so mmap
和 .apk mmap
。
我们可以观察 so 优化前后 .so mmap
的变化来判断优化是否有效果。
不过还有另外一个问题:Android 应用中通常有很多 so,所以没法通过 .so mmap
来判断单个 so 的优化效果。该怎么办?
maps 文件
判断单个 so 的优化效果的方法是查看和分析进程对应的 proc/<pid>/maps
文件。
Understanding-linux-proc-id-maps 对 maps
文件有介绍。
Each row in /proc/$PID/maps describes a region of contiguous virtual memory in a process or thread. Each row has the following fields:
1 | address perms offset dev inode pathname |
- address - 进程地址空间的起始地址
- permissions - 访问权限
- pathname - 如果该区域是从文件映射来的,pathname 为文件名
注意,直接在 adb shell 用 cat 查看 maps 文件可能会遇到 permission denied 问题。可以 run-as
命令来避免该问题。
1 | ➜ ✗ adb shell |
以下示例查看 com.example.flutter.image.flutter_image_demo
的 maps 文件。
1 | HWANE:/ $ run-as com.example.flutter.image.flutter_image_demo cat /proc/7331/maps | grep libandroid |
方便起见,可以写个脚本来解析 maps 文件以快速统计每个 so 文件占用内存的总大小。源码见 gist
1 | data_list = [] |
测试数据
- 测试目标:FlutterImageDemo、Flutter 项目优化前、Flutter 项目优化后
- 测试工具:
dumpsys meminfo
和run-as
- 测试指标:
libflutter.so
和libapp.so
文件大小.so mmap
- maps 文件中
libflutter.so
和libapp.so
大小
数据如下。
FlutterImageDemo
FlutterImageDemo 是一个简单的 Flutter 应用。
- 包名
com.example.flutter.image.flutter_image_demo
- 进程号 7331
- APK 包解压出来的
libflutter.so
和libapp.so
大小分别是 13.9MB 和 6.1MB
不得不吐槽下 Mac 上文件大小的计算方式对开发人员实现不友好。我重新算了一下,准确的大小分别是 13.2MB 和 5.8MB。
.so mmap
数据:
1 | adb shell dumpsys meminfo com.example.flutter.image.flutter_image_demo |
maps 数据如下:
1 | HWANE:/ $ run-as com.example.flutter.image.flutter_image_demo cat /proc/7331/maps | grep libflutter.so |
maps 解析后如下:
1 | /lib/arm64/libflutter.so 13.14453125 MB |
Flutter 项目优化前
从优化前的 APK 包解压出来的 libflutter.so
和 libapp.so
大小分别是 5.9MB 和 9.6MB
.so mmap
数据:
1 | adb shell dumpsys meminfo com.t.t.i.host |
maps 数据如下:
1 | HWANE:/ $ run-as com.t.t.i.host cat /proc/15191/maps | grep libflutter.so |
maps 解析后如下:
1 | Ccpa7w==/lib/arm/libflutter.so 5.9296875 MB |
Flutter 项目优化后
从优化后的 APK 包解压出来的 libflutter.so
和 libapp.so
大小分别是 5.9MB 和 8.6MB
.so mmap
数据:
1 | adb shell dumpsys meminfo com.t.t.i.host |
maps 数据如下:
1 | 127|HWANE:/ $ run-as com.t.t.i.host cat /proc/14331/maps | grep libflutter.so |
maps 解析后如下:
1 | V1HTdA==/lib/arm/libflutter.so 5.9296875 MB |
总结
- 对比
libflutter.so
和libapp.so
文件大小及 maps 的解析结果,发现数值几乎一致 - 对比
.so mmap
内存,看起来跟 so 文件大小相关性不明显 (??? 哪里出错了?)
libflutter.so文件 | libapp.so文件 | .so mmap |
maps文件解析 | |
---|---|---|---|---|
FlutterImageDemo | 13.2MB | 5.8MB | 13.7MB | 13.1MB和5.8MB |
优化前 | 5.9MB | 9.6MB | 15.8MB | 5.9MB和9.6MB |
优化后 | 5.9MB | 8.6MB | 15.7MB | 5.9MB和8.6MB |