结论先行:
受限于机型、Flutter版本,之后的测试结果可能不同(如Flutter团队优化了width、height,进行内存处理)
- cacheWidth,cacheHeight
- 直接resize,内存ok
- width、height 会先加载原图,再resize
- 会产生高峰,一张4.2MB的图,会猛增164.1MB
报错
E/flutter: [ERROR:flutter/lib/ui/painting/image_descriptor.cc(174)] Failed to allocate memory for bitmap of size 127844352B
E/flutter: [ERROR:flutter/lib/ui/painting/image_decoder.cc(289)] Could not decompress image.
测试项目
主页,3个按钮。分别跳转 仅含如下内容 页面
- Image.file 设置 width、height页面
- Image.file 设置 cacheWidth、cacheHeight页面
- 没有image的页面
内存抓取
测试具体数据
波峰的为使用width、height,较为平稳的是使用cacheWidth、cacheHeight。
原图数据
4.2MB, 4896 × 6528,按RGB8888解析后 4896 × 6528x4/1024/1024 = 121.921875 MB
解析到200x200
应为 200 * 200 * 4 / 1024/1024 = 0.15MB
跳转到如下页面
均为杀进程后,GC首页后 跳转页面
Image设置width、height为200时的页面:
异常时og提示,图片解析为127844352byte,121.921875 MB (与计算相符)
进入页面实际峰值差 306.4 - 142.3 = 164.1MB
(多出预计164.1 - 121.9 = 42.2MB, 因为是新页面 可能是别的内存)
进入页面平稳后 142.8 - 142.3 = 0.5MB
Image设为cacheWidth cacheHeight为200的页面
进入页面实际峰值差 155.4 - 144.6 = 10.8M
进入页面平稳后:145.2-144.3 = 0.9M
确保GC后测试:
峰值:
142.5 - 132.8 = 9.7MB
平稳后增加
136.5 - 132.8 = 3.7MB
没有Image的页面
进入页面实际峰值差 148.2 - 143.3 = 4.9M
确保GC后测试,
峰值
139 - 134.7 = 4.3MB
平稳后内存增加
137.8 - 134.7 = 3.1MB
数据总结
- 从width、height的数据可以明确看出,波峰时期直接将内存 解码到了native,增加了164MB,(高于纯图片解析121MB,应该是别的对象占用,具体有机会分析堆吧)
- 从Android 8 开始,bitmap数据被移到了native,这也是为啥后来不用recycle,或主动GC了,因为GC清理不了native 内存区域
- 从cache的数据可以看出,确实生效了,波峰才上升4.3MB。当然也高于期望的200x200图片解析的 0.15MB。 不过确实降了
- width、height会产生波峰,增加大小 > 图片解码内存+其他
本实验解决图片内存问题,详见 Flutter加载大图内存问题处理