优化 so 大小能否减少 Android 应用的内存?从原理上讲是可以的,实际效果如何?一起来看看吧。
(本文待完善)
相关文章:
背景 我们知道,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 2 address perms offset dev inode pathname 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm
address - 进程地址空间的起始地址
permissions - 访问权限
pathname - 如果该区域是从文件映射来的,pathname 为文件名
注意,直接在 adb shell 用 cat 查看 maps 文件可能会遇到 permission denied 问题。可以 run-as
命令来避免该问题。
1 2 3 4 5 ➜ ✗ adb shell HWANE:/ $ run-as run-as: usage: run-as <package-name> [--user <uid>] <command> [<args>] run-as com.example.flutter.image.flutter_image_demo cat /proc/7331/maps \ | grep libapp.so
以下示例查看 com.example.flutter.image.flutter_image_demo
的 maps 文件。
1 2 3 HWANE:/ $ run-as com.example.flutter.image.flutter_image_demo cat /proc/7331/maps | grep libandroid 7016edb000-7016ef6000 r-xp 00000000 fd:00 7502 /system/lib64/libandroid.so 7016ef7000-7016efb000 r--p 0001b000 fd:00 7502 /system/lib64/libandroid.so
方便起见,可以写个脚本来解析 maps 文件以快速统计每个 so 文件占用内存的总大小。源码见 gist
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 data_list = [] while (True ): raw_data = input ('paste maps string here: ' if len (data_list) == 0 else '' ) if (raw_data.strip() == '' ): break data_list.append(raw_data) mem_map = {} for item in data_list: tmp = item.split(' ' ) addr = tmp[0 ].split('-' ) if len (addr) == 2 : mem = (int (addr[1 ], 16 ) - int (addr[0 ], 16 )) / 1024.0 / 1024.0 key = tmp[-1 ][-30 :] if key in mem_map: mem_map[key].append(mem) else : li = [] li.append(mem) mem_map[key] = li else : pass for (k, v) in mem_map.items(): print (k, ' ' , sum (v), 'MB' )
测试数据
测试目标: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 2 3 4 5 6 7 adb shell dumpsys meminfo com.example.flutter.image.flutter_image_demo ** MEMINFO in pid 7331 [com.example.flutter.image.flutter_image_demo] ** Pss Private Private SwapPss Heap Heap Heap Total Dirty Clean Dirty Size Alloc Free ------ ------ ------ ------ ------ ------ ------ .so mmap 14010 584 12600 47
maps 数据如下:
1 2 3 4 5 6 7 8 9 10 HWANE:/ $ run-as com.example.flutter.image.flutter_image_demo cat /proc/7331/maps | grep libflutter.so 6fffee6000-70005d9000 r--p 00000000 103:08 39455 /data/app/com.example.flutter.image.flutter_image_demo-FcAoMElVHeoIhc0Ac6coTQ==/lib/arm64/libflutter.so 70005e6000-7000ae9000 r-xp 00700000 103:08 39455 /data/app/com.example.flutter.image.flutter_image_demo-FcAoMElVHeoIhc0Ac6coTQ==/lib/arm64/libflutter.so 7000af6000-7000bd6000 rw-p 00c10000 103:08 39455 /data/app/com.example.flutter.image.flutter_image_demo-FcAoMElVHeoIhc0Ac6coTQ==/lib/arm64/libflutter.so 7000bd6000-7000c25000 r--p 00cf0000 103:08 39455 /data/app/com.example.flutter.image.flutter_image_demo-FcAoMElVHeoIhc0Ac6coTQ==/lib/arm64/libflutter.so HWANE:/ $ run-as com.example.flutter.image.flutter_image_demo cat /proc/7331/maps | grep libapp.so 6fff5c3000-6fff5c5000 rw-p 00000000 103:08 45222 /data/app/com.example.flutter.image.flutter_image_demo-FcAoMElVHeoIhc0Ac6coTQ==/lib/arm64/libapp.so 6fff5c5000-6fff85d000 r-xp 00002000 103:08 45222 /data/app/com.example.flutter.image.flutter_image_demo-FcAoMElVHeoIhc0Ac6coTQ==/lib/arm64/libapp.so 6fff85d000-6fffb94000 r--p 0029a000 103:08 45222 /data/app/com.example.flutter.image.flutter_image_demo-FcAoMElVHeoIhc0Ac6coTQ==/lib/arm64/libapp.so 6fffb94000-6fffb95000 rw-p 005d1000 103:08 45222 /data/app/com.example.flutter.image.flutter_image_demo-FcAoMElVHeoIhc0Ac6coTQ==/lib/arm64/libapp.so
maps 解析后如下:
1 2 /lib/arm64/libflutter.so 13.14453125 MB /lib/arm64/libapp.so 5.8203125 MB
Flutter 项目优化前 从优化前的 APK 包解压出来的 libflutter.so
和 libapp.so
大小分别是 5.9MB 和 9.6MB
.so mmap
数据:
1 2 3 4 5 6 adb shell dumpsys meminfo com.t.t.i.host ** MEMINFO in pid 15191 [com.t.t.i.host] ** Pss Private Private SwapPss Heap Heap Heap Total Dirty Clean Dirty Size Alloc Free ------ ------ ------ ------ ------ ------ ------ .so mmap 16194 452 13896 127
maps 数据如下:
1 2 3 4 5 6 7 8 9 10 HWANE:/ $ run-as com.t.t.i.host cat /proc/15191/maps | grep libflutter.so c16c1000-c17ef000 r--p 00000000 103:08 132483 /data/app/com.t.t.i.host--zWkLmLHuo53FaZeCcpa7w==/lib/arm/libflutter.so c17ef000-c1baa000 r-xp 0012e000 103:08 132483 /data/app/com.t.t.i.host--zWkLmLHuo53FaZeCcpa7w==/lib/arm/libflutter.so c1baa000-c1c87000 rw-p 004e9000 103:08 132483 /data/app/com.t.t.i.host--zWkLmLHuo53FaZeCcpa7w==/lib/arm/libflutter.so c1c87000-c1caf000 r--p 005c6000 103:08 132483 /data/app/com.t.t.i.host--zWkLmLHuo53FaZeCcpa7w==/lib/arm/libflutter.so HWANE:/ $ run-as com.t.t.i.host cat /proc/15191/maps | grep libapp.so c0a0f000-c0a11000 rw-p 00000000 103:08 129024 /data/app/com.t.t.i.host--zWkLmLHuo53FaZeCcpa7w==/lib/arm/libapp.so c0a11000-c0f55000 r-xp 00002000 103:08 129024 /data/app/com.t.t.i.host--zWkLmLHuo53FaZeCcpa7w==/lib/arm/libapp.so c0f55000-c13a6000 r--p 00546000 103:08 129024 /data/app/com.t.t.i.host--zWkLmLHuo53FaZeCcpa7w==/lib/arm/libapp.so c13a6000-c13a7000 rw-p 00997000 103:08 129024 /data/app/com.t.t.i.host--zWkLmLHuo53FaZeCcpa7w==/lib/arm/libapp.so
maps 解析后如下:
1 2 Ccpa7w==/lib/arm/libflutter.so 5.9296875 MB FaZeCcpa7w==/lib/arm/libapp.so 9.59375 MB
Flutter 项目优化后 从优化后的 APK 包解压出来的 libflutter.so
和 libapp.so
大小分别是 5.9MB 和 8.6MB
.so mmap
数据:
1 2 3 4 5 6 7 adb shell dumpsys meminfo com.t.t.i.host ** MEMINFO in pid 14331 [com.t.t.i.host] ** Pss Private Private SwapPss Heap Heap Heap Total Dirty Clean Dirty Size Alloc Free ------ ------ ------ ------ ------ ------ ------ .so mmap 16053 452 13572 117
maps 数据如下:
1 2 3 4 5 6 7 8 9 10 127|HWANE:/ $ run-as com.t.t.i.host cat /proc/14331/maps | grep libflutter.so c154b000-c1679000 r--p 00000000 103:08 136617 /data/app/com.t.t.i.host-Cf28XWHWRKP40xhjV1HTdA==/lib/arm/libflutter.so c1679000-c1a34000 r-xp 0012e000 103:08 136617 /data/app/com.t.t.i.host-Cf28XWHWRKP40xhjV1HTdA==/lib/arm/libflutter.so c1a34000-c1b11000 rw-p 004e9000 103:08 136617 /data/app/com.t.t.i.host-Cf28XWHWRKP40xhjV1HTdA==/lib/arm/libflutter.so c1b11000-c1b39000 r--p 005c6000 103:08 136617 /data/app/com.t.t.i.host-Cf28XWHWRKP40xhjV1HTdA==/lib/arm/libflutter.so HWANE:/ $ run-as com.t.t.i.host cat /proc/14331/maps | grep libapp.so c0a8d000-c0a8f000 rw-p 00000000 103:08 131577 /data/app/com.t.t.i.host-Cf28XWHWRKP40xhjV1HTdA==/lib/arm/libapp.so c0a8f000-c0fd2000 r-xp 00002000 103:08 131577 /data/app/com.t.t.i.host-Cf28XWHWRKP40xhjV1HTdA==/lib/arm/libapp.so c0fd2000-c1328000 r--p 00545000 103:08 131577 /data/app/com.t.t.i.host-Cf28XWHWRKP40xhjV1HTdA==/lib/arm/libapp.so c1328000-c1329000 rw-p 0089b000 103:08 131577 /data/app/com.t.t.i.host-Cf28XWHWRKP40xhjV1HTdA==/lib/arm/libapp.so
maps 解析后如下:
1 2 V1HTdA==/lib/arm/libflutter.so 5.9296875 MB 0xhjV1HTdA==/lib/arm/libapp.so 8.609375 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