likes
comments
collection
share

Flutter 性能优化之降内存、降刷新篇

作者站长头像
站长
· 阅读数 33

1. 情景还原

Flutter 性能优化之降内存、降刷新篇Flutter 性能优化之降内存、降刷新篇

设想一下

APP 从点击启动到可以浏览页面需要 10 秒多;

玩一会儿页面卡住了;

玩一会儿流量 耗没了;

玩一会儿手机发烫了;

玩一会儿手机没电了;

玩一会儿应用闪退了;

作为用户,你会怎么做?重启、开骂、投诉、卸载...

作为开发,你会怎么做?领问题,解决。

‘我’收到的反馈

一、根据线上崩溃系统反馈,有一类崩溃出现过 2 个高点:2.19 号,3.12 号:

Flutter 性能优化之降内存、降刷新篇Flutter 性能优化之降内存、降刷新篇

根据崩溃栈,结合主线同学的排查结论,与之前商城团队线上出现过的崩溃问题现象一致:初步定位到图片组件问题:换图片组件 extended_image。

二、测试同学反馈,APP 页面偶现卡顿,上下滑动不流畅,影响体验。

行文至此,基于上述两点反馈,急需协调资源来着重处理下性能问题。

 2. 优化方向

基于以上两点,经团队内部推演、讨论:决定从 2 个维度尝试一下性能优化:降内存、降刷新。

2.1 优化方向定位

1.调研梳理所有优化方向,确定图片压缩、更换图片组件、降低页面刷新次数三个方向

Flutter 性能优化之降内存、降刷新篇Flutter 性能优化之降内存、降刷新篇

2.性能优化流程

Flutter 性能优化之降内存、降刷新篇

2.2 降内存- 图片优化

使用 iOS-Xcode、Android-Android Studio 开发工具来查看 APP 内存占用; 按照 Flutter 官方的性能优化指南,Flutter-profile 模式下,使用 devTools 查看 Flutter 内存占用;

查看电量(为后续 profile 模式分析 APP 耗电,提供查看窗口):

Flutter 性能优化之降内存、降刷新篇

Flutter 性能优化之降内存、降刷新篇

Flutter 性能优化之降内存、降刷新篇

由于智家 APP 壳工程 profile 模式正在攻克中,故暂时在 debug 模式下寻找内存泄漏点。

2.2.1 识别

2.2.1.1 高内存

全屋智能页为例:为固定测试变量,排除干扰项,屏蔽应用日志输出。

通过 Xcode 性能调试窗口可知,iOS 端智家 APP 的运行内存 1.32G 左右;

通过 Android Studio 的 profile 窗口可知,Android 端智家 APP 的运行内存在 1.4G 左右;

直觉:存在高内存问题。

Flutter 性能优化之降内存、降刷新篇

Flutter 性能优化之降内存、降刷新篇

2.2.1.2 过载图片

全屋智能页由 Flutter 开发,故切换到 Flutter 调试模式,继续分析(暂用 debug 模式,profile 模式暂不支持);

图片过载检测:切换到 Flutter Inspector,点击 Highlight Oversized Images

通过过载检测日志可知,有很多图片存在过载,需内存优化;

每张图片产生 20M 的额外内存;假设列表长度为 100,若内存回收不及时,理论上短时间内会产生 20M * 100 = 2G 左右内存浪费,存在卡顿、闪退风险。

Flutter 性能优化之降内存、降刷新篇

Flutter 性能优化之降内存、降刷新篇

随机下载一张设备图片查看:

file.c.haier.net/images/2020…

图片很大 -2000x2000 1.78M

Flutter 性能优化之降内存、降刷新篇

一个设备卡片的设备图标,显示区域只需要 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 的运行时内存占用:

Flutter 性能优化之降内存、降刷新篇

Flutter 性能优化之降内存、降刷新篇

此时检测图片过载情况:

Flutter 性能优化之降内存、降刷新篇

Flutter 性能优化之降内存、降刷新篇

图片 oss 压缩后,过载问题解决,APP 运行内存下降(debug 模式比 profile 模式略高):

  • iOS:1.32G -> 693M 内存降低 627M;
  • Android:1.4G -> 900M 内存降低 500M;

延伸:通过控制台可以发现,有很多图片存在不同程度的过载问题,此时可以逐一压缩验证,限于篇幅不展开赘述。

智家页按上述图片过载检测流程走一遍,也存在图片过载情况:

Flutter 性能优化之降内存、降刷新篇

抓取轮播图 下载查看-大小超限:

"pictureUrl" -> " oss-zjrs.haier.net/content/img… "

"pictureUrl" -> " oss-zjrs.haier.net/content/img… "

Flutter 性能优化之降内存、降刷新篇

与 UE 同学确认:该 Banner 的图片要求:宽/高=4; 这两张图都符合要求:一个是 3 倍图,一个是 2 倍图。(若尺寸不对或图片过大,可联系运营同学替换为合规图片)

图片合规,故前端压缩处理即可,有两种处理方式:

  1. 现有图片组件增加 ResizeImage 或 cacheWidth/cacheHeight;
  2. 替换有 cacheHeight 处理的新组件 extended_image;

从前后对比效果来看,选择第 2 种方案。

重新对图片过载检测,无过载提示,故 Banner 图片过载问题解决。

2.2.2.2 本地图片压缩

网络图片可以采用 oss 压缩;本地图片如何处理?

根据官方文档说明,以及图片过载检测控制台优化提示,给本地图片增加 cacheHight 或 cacheWidth;或使用 ResizeImage 组件包裹。

Flutter 性能优化之降内存、降刷新篇

注:cacheWidth/cacheHight = width/height * 像素密度,如:

Flutter 性能优化之降内存、降刷新篇

具体显示效果还是需自行参数调整、验证。

其他页面类似,按照此路径检测下是否存在图片过载情况。

2.2.2.3 换图片组件-ExtendedImage

经网络图片综合对比,目前 extended_image 组件表现最优。

extended_image 组件内置 ResizeImage-cache 处理,故会处理一部分图片压缩功能。

网络图片组件已知问题使用情况
CachedNetworkImage线上偶现崩溃(未 100%确认)线上 Flutter 页面还有使用,正在逐步切换;
NetworkImageImage.network()iOS 端:偶现断网再恢复网络图片不重新加载问题;(HDS-bug)替换组件:extended_image,解决
extended_image1 已知:商城、场景、首页;2 其他 Flutter 业务(智家、3+5、Flutter 主框架等)也在逐步替换为该网络组件;

2.2.3 效果

至此,降内存有所成效:

通过对网络图片 oss 压缩,对本地图片设置 cacheHight/cacheWigth,内存降低。

另:为防止出现线上的 11730 崩溃(图片组件),将网络图片组件逐步替换成 extended_image。

2.3 降刷新 - 刷新次数优化

降低页面刷新,从两个点去分析:动效/局部 UI 刷新 导致重绘;大量逻辑计算驱动页面刷新。

2.3.1 识别- 定位重绘区域

Flutter Inspector - Highlight Repaints

Flutter 性能优化之降内存、降刷新篇

Flutter 性能优化之降内存、降刷新篇

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 分钟内:

  1. 去掉属性上报相关日志 - 510 条
  2. 减少属性去重计算次数 - 510 次
  3. 时间越长,优化效果越明显

3. 总结

Flutter 性能优化的手段有很多,其中很重要两点:内存占用和页面刷新。

Flutter 的性能分析模式 profile 还在攻关中;本期使用 debug 模式;

所有性能参数 均比线上真实业务场景高 不能体现真实页面性能;只能取差值对比。

profile 模式下的 CPU、内存、电量、等优化手段,APP 壳工程暂不支持 profile 模式,未展开说明,可自行查阅官方优化指南:Flutter performance profiling

3.1 优化方案

本次通过以下几点尝试优化:

  1. 替换网络组件 extended_image;
  2. 图片 oss 压缩;
  3. 订阅关系优化:页面非前台及时解订阅,回前台重新订阅;
  4. 定位重绘区域:按需使用 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
评论
请登录