探究目的:
Flutter Module 与iOS混合开发目前最棘手的问题就是Flutter占用内存过高的情况,在几款iOS旗舰机型因其内存容量相对较大上所产生的表现好于几年前的几款机型,App的内存占用过高会导致App意外退出、切换至后台后会被系统快速清理,在App切换时会有切换出后返回时被重新打开的情况,占用了过多的内存空间,造成了不必要的消耗,降低了用户体验,就以上问题来探究一下Flutter 的内存占用问题。
用到的工具 Instruments Leaks 在使用过程中遇到问题可参照 iOS用Instruments Leaks调试出现问题解决方案 进行解决
名词解释:
All Heap & Anonymous VM
Heap 堆内存
Anonymous VM 虚拟内存
All Heap Allocations:进程运行过程中堆上分配的内存,简单理解就是实际分配的内存,包括所有的类实例,比如UIViewController、UIView、Foundation数据结构等。比如:
Malloc 512.00KiB: 分配的512k堆内存,类似还有 Malloc 80.00KiB等
CTRun: Core Text对象内存
All Anonymous:主要包含一些系统模块的内存占用以 VM: 开头
VM: IOSSurface:用于存储FBO、RBO等渲染数据的底层数据结构,是跨进程的,通常在CoreGraphics、OpenGLES、Metal之间传递纹理数据
VM: Stack: 栈内存(比如每个线程都会需要500KB)
VM: IOAccelerator:图片的CVPixelBuffer
进行测试
测试准备
测试设备:iPhone 6s Plus
iOS:14.4.1
Flutter:1.17.1
Flutter Boost:v1.17.1-hotfixes
测试步骤:
(0).进入App(此时Flutter engine随之启动)
(1).打开首个页面 -列表页( Flutter页面)
(2).进入第二个页面 - 详情页(Flutter页面)
(3).返回列表页列表页(Flutter页面)
(4).第二次进入 - 详情页1(Flutter页面)并随之返回列表页( Flutter页面)
(5).第三次进入 - 详情页2(Flutter页面)并随之返回列表页( Flutter页面)
(6).第四次进入 - 详情页3(Flutter页面)并随之返回列表页( Flutter页面)
(7).第五次进入 - 详情页4(Flutter页面)并随之返回列表页( Flutter页面)、
(8).返回列表页( Flutter页面)
(9).返回App首页
(10).无操作
测试时长:165s的测试中内存峰值为609.4MB
App启动后
未加载Flutter时App的初始内存占用
加载Flutter时App的初始内存占用
纯Flutter工程下的内存占用情况
测试设备iPhone X
iOS:13.7
Flutter:1.17.1
Flutter Boost:v1.17.1-hotfixes
测试时长:120s
模拟器运行纯Flutter工程下的内存占用情况
模拟器iPhone 12 Pro Max
iOS:14.4
Flutter:1.17.1
Flutter Boost:v1.17.1-hotfixes
测试时长:130s
(1).在1 - 2处之间操作与真机操作类似,但与真机出现的内存增高情况不完全相同,
(2).在2 - 3处时 停留在详情页面,对模拟器未做操作,出现了内存波动上升的情况,真机出现的内存情况相同。
(3).在3处时退出了详情页,有内存明显下降的情况,真机出现的内存情况不相同。
(4).在4处重新进入新的详情页内存升高。
(5).在5处退出详情页内存明显下降。
情况分析:
1.过多的堆空间占用,使用过的图片资源置于内存中没有得到释放和销毁,因为列表页、详情页的图片量大,导致Flutter整体占用内存空间过大相关的问题一直挥之不去。
2.模拟器与真机出现的内存情况不相同,在模拟器中频繁开启详情页没有明显的内存升高迹象但在真机中可以从内存占用情况中明显感知到。
解决思路:
1.适当的时候手动进行图片内存缓存的清理
PaintingBinding.instance.imageCache.clear();
(1)在位于1时,内存到达顶点,此时不进行任何交互操作;
(2)在位于2时,Flutter引擎做了内存清理,丢弃了不使用的内存占用;
(3)在位于3时,我们做了手动的图片缓存清理,但此清理对于Flutter而言不是实时去执行的;
(4)在位于4时,也就是我们等待了几秒钟后,Flutter引擎开始对缓存的图片进行清理
(5)位于5时,图片缓存被清理也包括废弃的资源清理完毕,内存回归到初始状态。
2.限制图片内存缓存体积
PaintingBinding.instance.imageCache.maximumSizeBytes = 1024 * 1024 * 40;//40MB
3.Flutter及Flutter Boost升级
Flutter Boost 1.17.1存在内存泄漏问题,在打开Flutter页面再退出后未能将页面释放掉,Flutter Boost 3.0flutter页面没有在引擎启动channel注册时启动,使得App在启动时内存不会像之前那样直接飙升,在打开Flutter页面后,页面内的代码随之执行,此时内存才会出现明显上升,相较于之前版本,内存情况有明显改观,列表停止滑动内存有少量下降迹象。
App启动后的初始内存情况得到一定改善;
4.列表滑动展示优化
复用机制,图片加载时机、滑动处理、异步运算等;
5.页面展示优化
结构调整、异步运算等;
6 .Flutter利用原生加载图片插件开发
熟悉Flutter的同学应该都知道,Flutter的视频组件是基于一个Flutter提供的一个叫“外接纹理”的技术实现的
分步优化后的内存情况:
1.限制图片内存缓存体积;
2.适当的时机进行图片内存缓存的清理例如退出Flutter视图时;
3.Flutter及Flutter Boost升级
在进行完以上三个优化点时,内存峰值相较之前有一定改观且以前出现的详情页退出内存不会释放的问题得到解决,(在4~5之间可明显看出);
而且在释放了图片内存缓存之后内存也得意下降至一个合理的水位;
测试环境
设备:iPhone X
iOS:14.4
Flutter:1.22.4
Flutter Boost:v3.0-beta.4
测试步骤:
(1).App初次启动后
(2).打开Flutter页面后(列表页)
(3).设置图片内存缓存限制并清理内存中的图片缓存
(4).进入详情页
(5).4~5之间进出详情页次数25次
(6).返回列表页
(7).执行清理内存中的图片缓存
(8).图片缓存清理后内存下降
(9).退出Flutter页面返回App首级内存稳定在此区间
(10).稳定在此区间