Flutter_29_Flutter性能监控和优化

33 篇文章 0 订阅
11 篇文章 3 订阅

Flutter、Golang、Python、编译原理、算法、Chrome原理学习系列文章抢先看请关注【码农帮派】

 

在Flutter中性能问题可以分为GPU线程问题、UI线程(CPU)问题。这两类问题可以通过Flutter提供的性能图层进行定位分析。

 

性能图层(Performance Overlay)

Flutter为了帮助开发者定位代码中的性能问题,提供了性能图层,它可以让我们快速的定位问题。

 

为了使用性能图层,我们需要以分析模式(Profile)来运行App,之前我们已经了解到Profile(分析)模式和Release模式一样,都需要在真机上才能运行,而且Profile模式和Release模式一样,使用AOT编译方式,去掉了诸如代码断言等额外的检查,这样才能在真实的用户体验环境中监测App的性能开销。

 

另一方面,模拟器使用的x86的指令集,而真机使用的ARM指令集。这两种指令集的二进制代码执行行为完全不同,因此真机和模拟器性能监控也是有差异的。

 

Profile(分析)模式是在Release(发布)模式的基础上,为分析工具提供了少量必要的应用追踪信息。在Android Studio上运行Profile模式:

也可以使用指令来运行Profile模式:​​​​​​​

// 以Profile模式运行Appflutter run --profile

 

界面渲染分析

通过Profile模式运行App之后,我们就可以使用Flutter提供的性能图层(Performance Overlay)来分析界面渲染性能问题。

 

性能图层会在当前应用的最上层,以Flutter引擎自绘的方式展示GPU和UI线程(CPU)的执行图表,每张图都代表了对应线程最近300帧的渲染情况。

上面的图就是性能图层,GPU渲染性能图表是上面,UI线程(CPU)渲染的性能图表在下面,其中绿色的条代表当前帧。

 

界面刷新的频率一般不能小于60Hz,为了保证60Hz的刷新频率,GPU线程和UI线程中执行每一帧的时间不能超过16ms(1/60秒)。要是某一帧的处理时间过长,就会产生界面卡顿的情况,下图中红色的条就表示界面的一次卡顿:

如果红色条出现在GPU线程图标,就说明渲染的图形过于复杂,导致无法快速的渲染;如果红色条出现在UI线程的图表,就说明Dart在主线程中执行了耗时的任务,消耗了大量的资源,这时我们就需要优化代码,或将耗时的操作放到异步线程中进行。

 

GPU问题定位

GPU的渲染问题主要是底层渲染耗时。有时候Widget树的构建很简单,但是GPU线程的渲染却很耗时。比如:

(1)当GPU渲染涉及到Widget的裁剪、蒙层这类多视图叠加的渲染;

(2)缺少缓存导致静态图像反复绘制,也会导致GPU渲染线程的速度。

 

Flutter提供了两个参数开关:

  • checkerboardOffscreenLayers检查多视图叠加渲染性能;

  • checkerboardRasterCacheImages检查缓存图片性能。

 

checkerboardOffscreenLayers

多视图叠加通常会用到Canvas里面的saveLayer方法,这个方法可以用来实现一些特定的效果(比如半透明),但是由于saveLayer方法的底层实现会在GPU渲染上对多图层进行反复绘制,因此带来较大的性能开销。

 

针对saveLayer性能的监测,我们需要在MaterialApp的初始化方法中传入checkerboardOffscreenLayers参数,并设置为true,这样性能监测工具就会帮助我们监测多视图叠加的情况,会将使用saveLayer的Widget显示为网格状,并会随着界面的刷新而闪动。

 

我们需要明白的是,saveLayer是一个底层方法,我们并不会直接使用它,我们往往是通过一些功能组件间接的使用到了saveLayer方法。

 

下面的代码使用了CupertinoPageScaffold与CupertinoNavigationBar实现了一个动态模糊的效果:

CupertinoPageScaffold(  // 动态模糊导航栏    navigationBar: CupertinoNavigationBar(),    child: ListView.builder(      itemCount: 100,      // 为列表创建 100 个不同颜色的 RowItem      itemBuilder: (context, index)=>TabRowItem(          index: index,          lastItem: index == 100 - 1,         // 设置不同的颜色         color: colorItems[index],         colorName: colorNameItems[index],      ),   ),);

 

动态模糊的NavigationBar如下:

 

当我们开启checkerboardOffscreenLayers之后,可以看到视图蒙层效果对GPU的渲染压力导致性能视图频繁闪动:

 

checkerboardRasterCacheImages

另外一个比较消耗资源的操作是图像的渲染,这是因为图像渲染涉及到I/O、GPU操作、以及不同通道的数据格式转换,因此图像的渲染会占用比较多的系统资源。Flutter为了缓解GPU压力,提供了多层缓存快照,这样Widget重建时就无需重复绘制静态图像了。

 

同样的,我们可以在MaterialApp中开启checkerboardRasterCacheImags参数,来检测界面重绘是静态图像缓存状态。

 

为了提高静态图像显示性能,我们可以将需要缓存的静态图像放到RepaintBoundary中,RepaintBoundary可以确定Widget树的重绘边界,如果图像足够复杂,Flutter引擎会自动进行缓存,避免重复绘制。当然,因为缓存资源有限,如果Flutter引擎认为当前的Widget不够复杂,就会忽略RepaintBoundary。

 

下面的代码展示了RepaintBoundary的使用方法:

RepaintBoundary(  child: Center(    child: Container(      color: Colors.black,      height: 10.0,      width: 10.0,    ),));

 

UI线程问题定位

GPU线程问题的定位涉及到底层渲染性能的优化,UI线程问题的定位就是因为我们在开发过程中,在主Isolate中存在比较耗时的代码,导致界面卡顿,比如build方法中进行复杂的运算、在主Isolate中同步执行耗时的I/O操作等等,这些都会增加CPU处理的时间,拖慢App响应速度。

 

针对UI线程的问题,Flutter提供了Performance工具进行定位,它记录了App执行的轨迹信息。Performance能够以时间轴的方式展示CPU的调用栈和执行情况,以此分析应用性能。

 

在Android Studio中找到 “Open DevTools“,点击就可以在浏览器中打开Performance工具:

 

下面的代码中,我们在build方法中计算1w次MD5的数值,以此观察Performance的记录情况:

class MyHomePage extends StatelessWidget {  MyHomePage({Key key}) : super(key: key);   String generateMd5(String data) {    //MD5 固定算法    var content = new Utf8Encoder().convert(data);    var digest = md5.convert(content);    return hex.encode(digest.bytes);  }   @override  Widget build(BuildContext context) {    return Scaffold(      appBar: AppBar(title: Text('demo')),      body: ListView.builder(          itemCount: 30,// 列表元素个数          itemBuilder: (context, index) {            // 反复迭代计算 MD5            String str = '1234567890abcdefghijklmnopqrstuvwxyz';            for(int i = 0;i<10000;i++) {              str = generateMd5(str);            }            return ListTile(title: Text("Index : $index"), subtitle: Text(str));          }// 列表项创建方法      ),    );  }}

 

当我们需要使用Performance的时候,需要手动点击 Record 按钮主动触发Performance进行CPU数据采集,然后我们就可以在真机设备上进行操作,一顿操作之后就可以在网页上看到记录的信息:

Performance记录的应用执行状况叫做CPU帧图,也被称为火焰图。它是用来记录代码执行情况的图,用来展示CPU的调用栈,表示了CPU的繁忙状况。

其中纵轴(y轴)表示调用栈,每一层都是一个函数,调用栈越深,执行时间越长;横轴(x轴)表示该函数在每个单位时间内被采样到的次数,一个函数在x轴长度越长,就表示它被采样的次数越多,执行时间越长。

针对这些耗时的操作,我们可以使用Isolate进行

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值