Flutter 性能优化之降内存、降刷新篇
1. 情景还原
设想一下
APP 从点击启动到可以浏览页面需要 10 秒多;
玩一会儿页面卡住了;
玩一会儿流量 耗没了;
玩一会儿手机发烫了;
玩一会儿手机没电了;
玩一会儿应用闪退了;
作为用户,你会怎么做?重启、开骂、投诉、卸载...
作为开发,你会怎么做?领问题,解决。
‘我’收到的反馈
一、根据线上崩溃系统反馈,有一类崩溃出现过 2 个高点:2.19 号,3.12 号:
根据崩溃栈,结合主线同学的排查结论,与之前商城团队线上出现过的崩溃问题现象一致:初步定位到图片组件问题:换图片组件 extended_image。
二、测试同学反馈,APP 页面偶现卡顿,上下滑动不流畅,影响体验。
行文至此,基于上述两点反馈,急需协调资源来着重处理下性能问题。
2. 优化方向
基于以上两点,经团队内部推演、讨论:决定从 2 个维度尝试一下性能优化:降内存、降刷新。
2.1 优化方向定位
1.调研梳理所有优化方向,确定图片压缩、更换图片组件、降低页面刷新次数三个方向
2.性能优化流程
2.2 降内存- 图片优化
使用 iOS-Xcode、Android-Android Studio 开发工具来查看 APP 内存占用; 按照 Flutter 官方的性能优化指南,Flutter-profile 模式下,使用 devTools 查看 Flutter 内存占用;
查看电量(为后续 profile 模式分析 APP 耗电,提供查看窗口):
由于智家 APP 壳工程 profile 模式正在攻克中,故暂时在 debug 模式下寻找内存泄漏点。
2.2.1 识别
2.2.1.1 高内存
以全屋智能页为例:为固定测试变量,排除干扰项,屏蔽应用日志输出。
通过 Xcode 性能调试窗口可知,iOS 端智家 APP 的运行内存 1.32G 左右;
通过 Android Studio 的 profile 窗口可知,Android 端智家 APP 的运行内存在 1.4G 左右;
直觉:存在高内存问题。
2.2.1.2 过载图片
全屋智能页由 Flutter 开发,故切换到 Flutter 调试模式,继续分析(暂用 debug 模式,profile 模式暂不支持);
图片过载检测:切换到 Flutter Inspector,点击 Highlight Oversized Images:
通过过载检测日志可知,有很多图片存在过载,需内存优化;
每张图片产生 20M 的额外内存;假设列表长度为 100,若内存回收不及时,理论上短时间内会产生 20M * 100 = 2G 左右内存浪费,存在卡顿、闪退风险。
随机下载一张设备图片查看:
图片很大 -2000x2000 1.78M:
一个设备卡片的设备图标,显示区域只需要 48x48,网络图是 2000x2000,优化空间很大。
2.2.2 方案
2.2.2.1 网络图片压缩
与海极网同学确认,设备图片存放在阿里云 oss 服务器,故可以使用 oss 图片压缩参数:
原始图片:file.c.haier.net/images/2020…
前端适配:file.c.haier.net/images/2020… ?x-oss-process=image/resize,m_fixed,h_100,w_100
(注:压缩尺寸设置过小会造成图片失真,具体压缩尺寸需根据显示区域自行调整)
(阿里云 OSS 图片处理-官方指南:OSS 图片处理中的图片缩放功能参数及示例_对象存储-阿里云帮助中心)
图片压缩后,再次检测 APP 的运行时内存占用:
此时检测图片过载情况:
图片 oss 压缩后,过载问题解决,APP 运行内存下降(debug 模式比 profile 模式略高):
- iOS:1.32G -> 693M 内存降低 627M;
- Android:1.4G -> 900M 内存降低 500M;
延伸:通过控制台可以发现,有很多图片存在不同程度的过载问题,此时可以逐一压缩验证,限于篇幅不展开赘述。
智家页按上述图片过载检测流程走一遍,也存在图片过载情况:
抓取轮播图 下载查看-大小超限:
"pictureUrl" -> " oss-zjrs.haier.net/content/img… "
"pictureUrl" -> " oss-zjrs.haier.net/content/img… "
与 UE 同学确认:该 Banner 的图片要求:宽/高=4; 这两张图都符合要求:一个是 3 倍图,一个是 2 倍图。(若尺寸不对或图片过大,可联系运营同学替换为合规图片)
图片合规,故前端压缩处理即可,有两种处理方式:
- 现有图片组件增加 ResizeImage 或 cacheWidth/cacheHeight;
- 替换有 cacheHeight 处理的新组件 extended_image;
从前后对比效果来看,选择第 2 种方案。
重新对图片过载检测,无过载提示,故 Banner 图片过载问题解决。
2.2.2.2 本地图片压缩
网络图片可以采用 oss 压缩;本地图片如何处理?
根据官方文档说明,以及图片过载检测控制台优化提示,给本地图片增加 cacheHight 或 cacheWidth;或使用 ResizeImage 组件包裹。
注:cacheWidth/cacheHight = width/height * 像素密度,如:
具体显示效果还是需自行参数调整、验证。
其他页面类似,按照此路径检测下是否存在图片过载情况。
2.2.2.3 换图片组件-ExtendedImage
经网络图片综合对比,目前 extended_image 组件表现最优。
extended_image 组件内置 ResizeImage-cache 处理,故会处理一部分图片压缩功能。
网络图片组件 | 已知问题 | 使用情况 |
CachedNetworkImage | 线上偶现崩溃(未 100%确认) | 线上 Flutter 页面还有使用,正在逐步切换; |
NetworkImageImage.network() | iOS 端:偶现断网再恢复网络图片不重新加载问题;(HDS-bug) | 替换组件:extended_image,解决 |
extended_image | 无 | 1 已知:商城、场景、首页;2 其他 Flutter 业务(智家、3+5、Flutter 主框架等)也在逐步替换为该网络组件; |
2.2.3 效果
至此,降内存有所成效:
通过对网络图片 oss 压缩,对本地图片设置 cacheHight/cacheWigth,内存降低。
另:为防止出现线上的 11730 崩溃(图片组件),将网络图片组件逐步替换成 extended_image。
2.3 降刷新 - 刷新次数优化
降低页面刷新,从两个点去分析:动效/局部 UI 刷新 导致重绘;大量逻辑计算驱动页面刷新。
2.3.1 识别- 定位重绘区域
Flutter Inspector - Highlight Repaints
UI 组件周边会出现彩色边框,UI 重绘时彩色边框会动态变色,类似跑马灯(如上图 gif),有 UI 重绘。
根据官方性能优化指南,若出现组件 A 重绘(动效、轮播等):
- 使用重绘组件包裹 A:RepaintBoundary Widget ;该组件会创建额外绘制画布
- 缺点是:增加一定内存消耗
从现象来看,直接页轮播图并未造成其他区域重绘,故无需特殊处理;若引起其他区域重绘,需逐步排查解决。
各页面可根据重绘情况,酌情考虑优化方案(控制 setState 粒度、引入全局状态管理-redux/Provider、拆分 ViewModel、减少 build() 操作 等)。
2.3.2 方案-订阅关系优化
经过逻辑梳理,发现一个点:智家页的属性订阅、解订阅逻辑存在优化空间。
页面销毁、无设备时才进行设备解订阅,比较难触发; 页面不在前台时订阅关系仍在,会造成不必要的属性去重计算和日志输出,造成 CPU、内存浪费。
打开 APP 日志开关,抓取日志验证:卡片列表稳定后-页面处在非前台,抓取 1 分钟日志,过滤属性变化相关日志:
优化前:vm_update 510 条左右 * N 分钟
理论上:日志量和属性去重计算次数 与时间呈线性关系:y = ax + b
订阅关系优化:
订阅关系优化 | 订阅时机 | 解订阅时机 |
优化前 | 1 设备列表初始化-订阅属性变化; 2 设备列表变化-订阅属性变化; | 1 设备列表为空-解订阅属性变化; 2 页面销毁 dispose()-解订阅属性变化; |
优化后 | 1 设备列表初始化-订阅属性变化; 2 设备列表变化-订阅属性变化; 3 页面进入前台-订阅属性变化; | 1 设备列表为空-解订阅属性变化; 2 页面销毁 dispose()-解订阅属性变化; 3 页面进入非前台-解订阅属性变化; |
订阅关系优化后,打开 APP 日志开关,抓取日志验证: 卡片列表稳定后-页面处在非前台,抓取 1 分钟日志,过滤属性变化相关日志:
优化后:vm_update 恒定 20 条左右(理论值为 0,由于日志抓取的时间前后误差-导致出现脏数据)。
时间越长,日志量和属性去重计算次数 下降越明显,CPU 使用率降低越明显。
(由于 APP 开启全量日志后,对比条件加入了日志 IO 干扰,无法准确描述订阅优化前后 CPU 使用率对比)。
2.3.3 效果
页面非前台解订阅,页面回前台重新订阅,100 个设备 1 分钟内:
- 去掉属性上报相关日志 - 510 条
- 减少属性去重计算次数 - 510 次
- 时间越长,优化效果越明显
3. 总结
Flutter 性能优化的手段有很多,其中很重要两点:内存占用和页面刷新。
Flutter 的性能分析模式 profile 还在攻关中;本期使用 debug 模式;
所有性能参数 均比线上真实业务场景高 不能体现真实页面性能;只能取差值对比。
profile 模式下的 CPU、内存、电量、等优化手段,APP 壳工程暂不支持 profile 模式,未展开说明,可自行查阅官方优化指南:Flutter performance profiling。
3.1 优化方案
本次通过以下几点尝试优化:
- 替换网络组件 extended_image;
- 图片 oss 压缩;
- 订阅关系优化:页面非前台及时解订阅,回前台重新订阅;
- 定位重绘区域:按需使用 RepaintBoundary 组件。
3.2 优化效果
降内存-内存使用明显下降:100 个设备,Android 平均下降 500M,iOS 平均下降 600M;
降刷新-属性去重计算下降:订阅关系优化后,抓取 1 分钟日志输出,减少 510 条;去重计算减少 510 条;
崩溃率-Flutter 图片崩溃率:待上线后通过监控系统,进一步跟踪线上崩溃趋势。
3.3 优化指南
官方性能优化指南路径清晰,方法全面,建议各位同学都尝试一下,发现更多优化点,让 APP 更流畅、更健壮。
性能最佳实践:Performance best practices | Flutter
官方性能分析:Flutter performance profiling | Flutter
4. 参考
5. 团队介绍
「三翼鸟数字化技术平台-网器管理平台」负责网器设备基础数据和计算、规则引擎、网器绑定、网器控制、安防音视频、网器跨平台接入验证等业务,服务产业及海尔智家线上用户;负责网器管理平台建设,提供产业设备基础数据底座、研发产业跨平台网器管理工具等,致力于提升用户交互体验和网器产品的智能化水平。
转载自:https://juejin.cn/post/7288963909582553122