flutter性能分析

前言:

在性能优化之前,我们需要知道Flutter重构的逻辑。
Android中我们知道绘制需要的三个步骤是 measurelayoutdraw
Flutter对应的是buildlayoutpaint
他的重构是基于一种标脏和重新创建的方式进行的,所以我们的性能影响一般来自于一个复杂界面的不断重建。可能你只需要修改一个很小的部分,也就是很小的一个子树需要进行修改,那么在代码没有规范的情况下,可能会出现整个界面的刷新,这样我们的性能可能就要下降了数倍。

一、官网文档地址:

二、快速定位widget代码

Flutter Inspector 工具快速定位 Widget 代码

非常实用

1.刷新

2.定位

3.点击手机上的widget就能定位到widget在代码中的位置了

三、检视 widget 重建性能

参考:Flutter渲染性能优化全攻略(解决应用卡顿)_中间件兴趣的技术博客_51CTO博客

在 Android Studio 中,找到 Flutter Performance (View > Tool Windows > Flutter Performance),就可以直接看到正在重建的 widget 数量。

注意:不能使用命令行运行

四、代码优化工具 : PerformanceOverlay

注:因为debug模式下Flutter的性能会受到比较大的限制,为了还原检测的真实性我们需要在分析模式运行APP

  • 在 Android Studio 和 IntelliJ 使用 Run > Flutter Run main.dart in Profile Mode 选项

  • 或者通过命令行使用 --profile 参数运行
    • flutter run --profile


A. 在 Flutter 项目中打开 PerformanceOverlay

1.首先打开 PerformanceOverlay 工具,在 AndroidStudio -> Preference -> Language&Frameworks -> Flutter 中打开相应开关,如图:

2.然后 run 我们的APP,就可以在AS的左边看到 Flutter Inspector的窗口(标记),如图:

3.然后打开 PerformanceOverlay,点击Flutter Inspector 窗口左上角树状图按钮(标记2) ,即可在屏幕上显示当前UI帧率和GPU帧率的波图。

B. aar 模式混合开发的项目 打开 Flutter Inspector

只需要在Flutter 项目的根布局或者入口布局的 MaterialApp 的Widget中加入即可:

```

showPerformanceOverlay: true 

```

C. PerformanceOverlay 分析

打开PerformanceOverlay后,我们APP会增加两个浮层,如图:

1. 绿色代表当前帧,如果页面UI有变动,图表便会不断绘制。
2. 蒙版上有两个图表,每个图表有三个格,每一格代表16ms,如果大多数帧都没超过第一行,说明达到了期望的帧率。
3. 蒙版上有两个图表,分别表示UI 线程帧率和 GPU 线程帧率。
       UI 线程主要执行虚拟机中的Dart代码,包括制作视图树和业务逻辑。
       GPU 线程主要绘制视图树,即渲染视图。

4. 优化建议:
      1. 如果 UI 线程当前帧率由绿色变为红色,那么可能是执行了某个较耗时的函数,或者函数调用过多,算法复杂度高。
      解决方法:
      此处多为业务逻辑,优化业务逻辑代码为主。
      耗时的计算放到独立的 isolate 去执行。

      2. 如果 GPU 线程当前帧率由绿色变为红色,那么可能是要绘制的图形过于复杂,或者执行了过多GPU操作。
      解决方法:
      1.优化Widget的布局,减少不必要的层级。
      具体属性 Widget 设置到具体的Widget。

      2.载入的资源大,如:大图片

5.GPU问题定位

GPU渲染问题主要集中在底层渲染耗时上,有时候 Widget 树虽然构造起来容易,但在 GPU 线程下的渲染却很耗时。例如,涉及 Widget 裁剪、蒙层这类多视图叠加渲染,或是由于缺少缓存导致静态图像的反复绘制,都会明显拖慢 GPU 的渲染速度。

接下来,使用性能图层提供的两项参数,即检查多视图叠加的视图渲染开关 checkerboardOffscreenLayers和检查缓存的图像开关checkerboardRasterCacheImages来检查这两种情况。

checkerboardOffscreenLayers

多视图叠加通常会用到 Canvas 里的 savaLayer 方法,这个方法在实现一些特定的效果(比如半透明)时非常有用,但由于其底层实现会在 GPU 渲染上涉及多图层的反复绘制,因此会带来较大的性能问题。

对于 saveLayer 方法使用情况的检查,我们只需要在 MaterialApp 的初始化方法中,将 checkerboardOffscreenLayers 开关设置为 true,分析工具就会自动帮我们检测多视图叠加的情况。使用了 saveLayer 的 Widget 会自动显示为棋盘格式,并随着页面刷新而闪烁。不过,saveLayer 是一个较为底层的绘制方法,因此我们一般不会直接使用它,而是会通过一些功能性 Widget,在涉及需要剪切或半透明蒙层的场景中间接地使用。所以一旦遇到这种情况,我们需要思考一下是否一定要这么做,能不能通过其他方式来实现呢?


Flutter 实现的一些效果背后可能会使用 saveLayer() 这个代价很大的方法。

为什么 saveLayer 代价大?
调用 saveLayer() 会开辟一片离屏缓冲区。将内容绘制到离屏缓冲区可能会触发渲染目标切换,这些切换在较早期的 GPU 中特别慢。

——来自 flutter.cn,https://flutter.cn/docs/testing/best-practices

如下这几个组件,底层都会触发 saveLayer() 的调用,同样也都会导致性能的损耗:

  • ShaderMask
  • ColorFilter
  • Chip,当 disabledColorAlpha != 0xff 的时候,会调用saveLayer()。
  • Text,如果有 overflowShader,可能调用 saveLayer() ,

官方也给了我们一些非常需要注意的优化点:

由于 Opacity 会使用屏幕外缓冲区直接使目标组件中不透明,因此能不用 Opacity Widget,就尽量不要用。有关将透明度直接应用于图像的示例,请参见 Transparent image,比使用 Opacity widget 更快,性能更好。

要在图像中实现淡入淡出,请考虑使用 FadeInImage 小部件,该小部件使用 GPU 的片段着色器应用渐变不透明度。

很多场景下,我们确实没必要直接使用 Opacity 改变透明度,如要作用于一个图片的时候可以直接使用透明的图片,或者直接使用 Container:Container(color: Color.fromRGBO(255, 0, 0, 0.5))

Clipping 不会调用 saveLayer()(除非明确使用 Clip.antiAliasWithSaveLayer),因此这些操作没有 Opacity 那么耗时,但仍然很耗时,所以请谨慎使用。

要创建带圆角的矩形,而不是应用剪切矩形,请考虑使用很多 widget 都提供的 borderRadius属性。
 
参考: https://blog.51cto.com/u_15023237/2617680

checkerboardRasterCacheImages

从资源的角度看,另一类非常消耗性能的操作是渲染图像,因为图像渲染会涉及 I/O、GPU 存储以及不同通道的数据格式转换,因此渲染过程的构建需要消耗大量资源。为了缓解 GPU 的压力,Flutter 提供了多层次的缓存快照,这样 Widget 重建时就无需重新绘制静态图像了。

与检查多视图叠加渲染的 checkerboardOffscreenLayers 参数类似,Flutter 提供了检查缓存图像的开关 checkerboardRasterCacheImages,来检测在界面重绘时频繁闪烁的图像。

为了提高静态图像显示性能,我们可以把需要静态缓存的图像加到 RepaintBoundary 中,RepaintBoundary 可以确定 Widget 树的重绘边界,如果图像足够复杂,Flutter 引擎会自动将其缓存,从而避免重复刷新。当然,因为缓存资源有限,如果引擎认为图像不够复杂,也可能会忽略 RepaintBoundary。下面的代码展示了通过 RepaintBoundary,将一个静态复合 Widget 加入缓存的具体用法,如下所示。


RepaintBoundary(//设置静态缓存图像
  child: Center(
    child: Container(
      color: Colors.black,
      height: 10.0,
      width: 10.0,
    ),
));

RepaintBoundary的使用

例如:一个小动画可能会导致整个页面重绘,这个时候使用 RepaintBoundary Widget 包裹它,可以将重绘范围缩小至本身所占用的区域,这样就可以减少绘制消耗。

使用场景

例如 页面的进度条动画刷新时会导致整个布局频繁重绘

缺点

使用 RepaintBoundary Widget 会创建额外的绘制画布,这将会增加一定的内存消耗

6.问题定位

  • 加入测试代码
void imBusy() {
  for (var i = 0; i < 9999999; i++) {}
}

@override
Widget build(BuildContext context) {
  imBusy();
  ...
}
  • 视图

为了方便排查 勾选这三个项目,剩下的就是你自己的函数

Cpu Profile > Cpu Flame Chart 图标能查看具体的函数

需要点击 Record , 然后你操作界面, 记得 Stop

这边也是过滤掉系统的 ,三个都勾选上

自己项目首页优化前后效果

                              

五、内存优化工具 : Observatory

Observatory是用于分析和调试Dart代码的工具,因为Flutter自带Dart VM,所以也可以用Observatory

Observatory打开方式

1. 在 Flutter Inspector 中点击秒表图标,如图:

2. 在命令行输入(要求有main 函数):
```
flutter run
```
3. 运行成功后会显示:

4. 点击网址进入,点击左下角选择当前线程,如图:

5. 进入线程页面后,我们可以再 Main 菜单里看到许多数据分析,包括CPU分析和Log台等,我们点击 allocation profile ,如图所示:

6. 进入 allocation profile

内存分析

1. 在这个页面,我们可以看到程序内存的分析:

  • New generation: 新创建的对象,一般来说对象比较小,生命周期短,如local 变量。在这里GC活动频繁。
  • Old generation:从GC中存活下来的New generation将会转移到Old generation,它比新生代空间大,更适合大的对象和生命周期长的对象。

2. 该图表提供一些功能,能帮我们更方便的排查内存泄漏。

  • 点击右上角的 “Auto-refresh on GC ” 选项来实时的检测内存表现;
  • 点击顶部的按钮 “ GC ” 来实现手动GC;
  • 点击顶部的 “ Reset Accumulator” 可以清空数据。

六、总结

在 Flutter 中,性能分析过程可以分为 GPU 线程问题定位和 UI 线程(CPU)问题定位,而它们都需要在真机上以分析模式(Profile)启动应用,并通过性能图层分析大致的渲染问题范围。
一旦确认问题存在,接下来就需要利用 Flutter 所提供的分析工具来定位问题原因了。关于 GPU 线程渲染问题,我们可以重点检查应用中是否存在多视图叠加渲染,或是静态图像反复刷新的现象。而 UI 线程渲染问题,我们则是通过 Performance 工具记录的火焰图(CPU 帧图),分析代码耗时来找出应用执行瓶颈。

总的来说,由于 Flutter 采用基于声明式的 UI 设计理念,以数据驱动渲染,并采用 Widget->Element->RenderObject 三层结构,屏蔽了无谓的界面刷新,能够保证绝大多数情况下我们构建的应用都是高性能的,所以在使用分析工具检测出性能问题之后,通常我们并不需要做太多的细节优化工作,只需要在改造过程中避开一些常见的坑,就可以获得优异的性能。同时,为了避免造成性能问题,还应该从以下几个方面着手:

控制 build 方法耗时,将 Widget 拆小,避免直接返回一个巨大的 Widget,这样 Widget 会享有更细粒度的重建和复用;

尽量不要为 Widget 设置半透明效果,而是考虑用图片的形式代替,这样被遮挡的 Widget 部分区域就不需要绘制了;

对列表采用懒加载而不是直接一次性创建所有的子 Widget,这样视图的初始化时间就减少了。

  • 尽量使用无状态的类组件来代替函数式的组件
  • 尽量保持build方法的纯净,减少跟UI无关的逻辑处理
  • 尽量使用const final等修饰符来避免重复创建新的组件

参考链接:https://blog.csdn.net/qizewei123/article/details/102767893

flutter性能优化大全_flutter_君不见JJ-华为云开发者联盟

深入探索Flutter性能优化 - 掘金

使用篇参考:http://t.csdn.cn/7ScOH

Flutter 性能分析_测试0901-1-CSDN博客

Flutter项目的调试技巧视频 Flutter项目的调试技巧--flutter视频教程-移动开发-CSDN程序员研修院

[Google Flutter 团队出品] 深入了解 Flutter 的高性能图形渲染 (GDD China ’18)_哔哩哔哩_bilibili

Flutter性能优化—UI_flutter_zhudaihai-CSDN学习社区

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值