logo
积分中心
Flutter 性能调优之性能分析工具与 trace 介绍
头像 鸿蒙小助手 2026-10-21 14:27:43    发布
16 浏览 3 点赞 1 收藏

本原创文章帖发布在华为开发者联盟社区,欢迎开发者前往访问评论交流,更多与该内容相关讨论,请点击原帖查看:

Flutter 性能调优之性能分析工具与 trace 介绍-华为开发者话题 | 华为开发者联盟


      Flutter 应用在鸿蒙(OpenHarmony)平台上的性能问题,通常表现为滑动卡顿、点击无反馈、页面加载迟缓等现象。定位这些问题需要理解 Flutter 的渲染流程与线程模型,并掌握 DevEco Studio Profiler 与 Flutter DevTools 两类工具的 trace 采集与解读方法。

      本文是 Flutter 鸿蒙性能定位系列的基础篇,介绍 Flutter 的渲染流程、线程模型、关键 trace 点以及两类性能分析工具的使用方法,为后续具体场景问题的定位提供基础。完成本文阅读后,如需深入定位具体问题,请继续阅读:

      Flutter性能调优之滑动卡顿问题介绍

      Flutter性能调优之点击响应和完成时延介绍

1. 前置条件

      • HarmonyOS 系统(5.0及以上版本),前台运行 Flutter 页面;

      • 分析工具:

         o DevEco Studio Profiler

         o Flutter DevTools

      本文截图使用的 Flutter 版本为 3.27.5-ohos-1.0.7

2. Flutter 线程模型

      Flutter 内部有四类线程,各自承担不同职责:

线程名称职责性能图层位置
平台线程平台主线程,插件代码与系统接口调用在此运行。在鸿蒙平台上即为应用主线程—
UI 线程在 Dart VM 中执行 Dart 代码,包括开发者代码与 Flutter 框架生成的代码。应用创建和展示场景时,UI线程首先构建图层树(layertree),并提交给 GPU 线程渲染。不要阻塞该线程性能图层下方
Raster 线程光栅化线程,又称 GPU 线程。拿到 layer tree 后交给图形库(Skia/Impeller)生成 GPU 指令完成光栅化。该线程变慢通常由 UI 线程产出的图层复杂度导致性能图层上方
I/O 线程执行高负载 I/O 操作以避免阻塞 UI 或 Raster 线程不显示

      注意:从 Flutter 3.29 版本起支持 UI 线程与平台线程合并。合并后,UI线程中原有的 trace 点都会出现在平台线程泳道中。

3. Flutter 渲染流程

      Flutter 采用”UI线程构建图层树 → Raster 线程光栅化 → 系统合成上屏”的渲染模型。一次完整的帧渲染经过以下阶段:

      一帧渲染流程

3.1 帧调度

      当输入事件到达、动画 tick 触发或setState标记 Element 为 dirty 时,Flutter通过Animator::RequestFrame向系统请求 vsync 信号。系统在下一个 vsync 到来时回调Animator::BeginFrame,UI线程开始一帧的工作。

3.2 UI 线程:构建图层树

      UI 线程收到 vsync 后执行四个子阶段,输出一棵LayerTree(图层树):


子阶段作用典型耗时来源
Animate(动画)派发Ticker/AnimationController回调,推进动画状态,可能触发setState动画回调中的重计算
Build(构建)调用 dirty Element 的build()重建 Widget 树,更新 Element 与 RenderObject 树超大范围重建、build中执行同步耗时操作(排序、JSON解析)
Layout(布局)对 RenderObject 树执行measure/layout,计算各节点位置与尺寸嵌套层级过深、IntrinsicHeight/Width多次测量
Paint(绘制)将 RenderObject 树绘制为LayerTree,记录各图层绘制指令复杂路径、阴影、saveLayer调用过多

      四个子阶段均在 UI 线程同步完成,任一阶段超时都会导致该帧 UI 线程耗时过长。构建完成的 LayerTree 通过Scene提交给Engine,由 Raster 线程消费。

3.3 Raster 线程:光栅化

      Raster 线程拿到 LayerTree 后执行GPURasterizer::Draw:

      1. 通过 binder 向 RenderService 进程申请buffer(对应ReuseBuffer标识),用于存储渲染结果;

      2. 遍历图层树,将绘制指令交由图形库(Skia/Impeller)执行,生成 GPU 指令并写入buffer;

      3. 渲染完成后释放buffer,交由系统合成。

      Raster 线程的耗时通常由 UI 线程产出的图层复杂度决定:saveLayer过多、复杂Shader、大量图片上传等都会拖慢光栅化。

3.4 系统合成上屏

      • RSMainThread::DoComposition:RenderService主线程从 buffer 中获取帧数据(对应acquire buffer),合成渲染树上各节点图层;

      • RSUniRenderThread/RenderFrame:GPU执行最终绘制,帧上屏。

      UI 线程与 Raster 线程的总耗时超过一帧预算(如 120Hz 下 8.33ms、90Hz 下11.1ms)时,会导致 RenderService 缺帧,表现为掉帧卡顿。

4. 关键 Trace 点

      下表按渲染流程顺序列出 Flutter 应用性能分析时需要关注的关键 trace 点,用于在 trace 中定位各阶段的起止:


阶段Trace 标记所在线程/泳道
系统输入上报H:originEventHandle code:mmi_service
应用收到触摸事件H:DispatchTouchEvent应用主线程
触摸事件投递至 FlutterH:flutter::Shell::OnPlatformViewDispatchPointerDataPacket应用主线程
Flutter UI 线程收到触摸事件H:flutter::Engine::DispatchPointerDataPacketui
请求新一帧绘制H:flutter::Animator::RequestFrameui
开始一帧绘制,生成图层树H:flutter::Animator::BeginFrame frame_number:ui
将图层树转为 GPU 指令并光栅化H:flutter::GPURasterizer::Drawraster
RenderService 合成各节点图层H:RSMainThread::DoCompositionrender_service
GPU 执行最终绘制H:RenderFrameRSUniRenderThread

      说明:UI线程与平台线程合并后,UI线程中原有的 trace 点都会出现在平台线程泳道中。

5. 使用 DevEco Studio Profiler 进行性能分析

      DevEco Studio Profiler 是 DevEco Studio 提供的场景化调优工具,其中 Frame 模板可以录制应用运行过程中的关键数据,用于深度分析卡顿丢帧、耗时长等问题。本节说明在 Flutter 性能分析场景下的使用方法,更通用的操作说明可参考Frame分析。

5.1 抓取 trace

      1. 使用 release 或 Profile 构建模式安装应用,连接设备;

      2. 打开 DevEco Studio → Profiler,选择设备与目标应用、进程,选择 Frame 模板,单击 Create Session 创建会话;

      3. 单击启动按钮开始录制,在设备上执行待分析操作,完成后停止录制并保存 trace 文件;

      4. 抓取完成后,收藏应用进程的ui、raster线程和 RenderService 主线程泳道,便于后续分析。

      收藏关键泳道

5.2 帧渲染跟踪:标识符匹配

      掌握帧渲染流程(§3)后,还需要掌握流程各单元之间的匹配方法,为每个单元寻找合适的标识符,才能在 trace 上正确串联一帧的完整渲染过程。

第一个标识:frame_number

      ui与raster线程之间的联系标识符是frame_number。收藏这两个线程并关联观察,会在 trace 上找到该标识符,这是 Flutter 应用帧渲染的第一个标识符:

      frame_number 标识

      • 如果frame_number未在ui和raster中出现,表明当前帧不是 Flutter 自渲染,需要重新定界性能问题。

第二个标识:ReuseBuffer / acquire buffer

      raster与render_service之间的联系标识符是ReuseBuffer。在raster线程flutter::GPURasterizer::Draw的 trace 过程中,会向 RenderService 进程申请 buffer 内存,用于存储渲染的帧内容。点击binder transaction的 trace 可以跳转到另一线程,查看对应的ReuseBuffer编号:

      ReuseBuffer 申请

      在render_service线程RSMainThread::DoComposition的 trace 过程中,会获取 buffer 内存里的帧数据,acquire buffer sequence中的编号与raster线程申请的ReuseBuffer编号一致:

      acquire buffer

      通过以上两个标识,可以识别 Flutter 应用到 RenderService 进程上的帧渲染链路。RenderService进程上后续单元目前没有直观的 trace 可供识别。

5.3 性能问题定界

      抓取 trace 并收藏关键泳道后,按帧渲染流程定界问题归属。下图 RenderService 缺失帧,是因为 UI 线程单帧耗时较长,超过一帧的时间(120帧率下,一帧为 8.33 毫秒):

      RenderService 缺失帧

      • 一帧渲染流程中,ui和raster加起来的总时长超过一帧时间,则性能问题可定界为 Flutter 侧问题;

         o 如上图,从ui线程代码执行开始(标记①),到raster线程代码执行结束(标记②)为止,超过了一帧时间,需进一步定位具体阶段。

5.4 性能问题定位

场景一:Flutter页面点击卡顿

      以某应用 Flutter 页面点击卡顿为例,定位过程如下:

      1. 使用 Profiler Frame 分析能力抓取该过程的trace,根据mmi_service泳道的 trace 点找到页面滑动过程,并点击 Frame 泳道下的子泳道 Display Vsync 可看到该过程的屏幕刷新率为89,Flutter页面各线程的单帧处理时间需控制在11.1ms(1000/90)以内,否则会出现滑动卡顿问题:

      2. 查看页面滑动附近ui线程的trace,发现ui线程在点击操作后flutter::DefaultPointerDataDispatcher::DispatchPacket耗时828ms,远超11.1ms:

      3. 在 Callstack 泳道的ui[65405]子泳道中查看ui线程单帧绘制时的调用栈,发现耗时主要集中在libflutter.so文件,但对应的是ui 线程中的点击事件,因此问题点在 Dart 代码点击事件的业务逻辑耗时太长:

6. 使用 Flutter DevTools 进行性能分析

      DevEco Studio Profiler 侧重系统侧 trace 分析,Flutter DevTools 侧重 Dart 侧帧级与事件级分析,两者互补。建议先用 Profiler 定界问题归属(UI线程还是 Raster 线程),再用 DevTools 深入 Dart 侧定位具体函数。

6.1 devtools 使用方式

      1. 连接真实设备,以 Profile 模式运行 Flutter 应用;

      2. 运行成功后,用浏览器打开 log 中输出的 devtools 调试地址,如http://127.0.0.1:9104?uri=http://127.0.0.1:54358/

6.2 打开 performance overlay

      在命令行中按P可以切换应用中 performance overlay 视图的显示或隐藏。下面的截图展示了 Flutter Gallery 样例的性能图层:

      performance overlay

      性能图层显示 Raster 线程(上)和 UI 线程(下)的叠加图,垂直的绿色条代表当前帧。红色竖条表明当前帧的渲染和绘制都很耗时,当两张图表都是红色时,应优先对 UI 线程(DartVM)进行诊断。

6.3 性能问题定界

      打开 DevTools 中的 Performance 界面,当在 “Flutter frames” 视图中看到一个红色或耗时较长的帧时,可这样操作:

      1. 点击有问题的帧,下方的时间线事件区域会同步更新,显示该帧内发生的所有事件:

      2. 在时间线中,会看到按线程(如 UI 线程、GPU线程)分类的事件流,事件以色块形式展示,色块宽度代表

      其耗时:

      3. 寻找耗时最长的事件。UI线程中异常的宽色块(例如一个 build 事件)通常就是性能瓶颈所在,可悬停或点击事件查看其详细信息与调用栈:

6.4 常见应用层问题与对应 trace 事件

UI 线程常见问题

      1. Build 阶段耗时过长:这是最常见的问题。火焰图中 Build 相关色块又宽又大,通常意味着build()方法执行了耗时同步操作(如大数据排序、JSON解析)或触发了超大范围的不必要重建。

         o 排查方法:开启 Track Widget Builds 选项,Timeline里会显示具体是哪个 Widget 的 build 方法被调用;结合 CPU Profiler 的火焰图或调用树,定位到具体耗时函数。

      2. Layout 阶段耗时:可能源于嵌套层级过深、使用了IntrinsicHeight/Width等需要多次测量布局的组件。

Raster 线程常见问题

      1. saveLayer()调用过多:这是 Raster 线程性能下降的头号元凶。saveLayer()会创建离屏缓冲区,非常消耗性能。DevTools的 Frame Analysis 标签页会直接给出类似 “Canvas.saveLayer() was called 16 times during this frame” 的警告。

         o 应用层原因:过度使用Opacity、ClipPath、ShaderMask或复杂的半透明重叠效果,这些都会触发隐式saveLayer()调用。

      2. 复杂的图形效果:过度使用阴影(PhysicalModel)、大量图片绘制等。

相关文档

      Flutter 性能调优之滑动卡顿问题介绍 (系列第二篇)

      Flutter 性能调优之点击响应和完成时延介绍 (系列第三篇)

DevEco Studio Profiler 调优工具介绍

      • DevEco Profiler 调优工具简介

      • 使用 Profiler 进行性能调优

      • Flutter 页面滑动卡顿问题分析

Flutter DevTools 调优介绍

      • Flutter 性能评估

      • Flutter 性能视图

      • Flutter 性能分析

----------------------------------------------------------------------------------------------------------

🔗 官网开发者学堂视频:https://developer.huawei.com/consumer/cn/training/result?type2List=201783644516849879&orderBy=1&courseType=5?ha_source=zxqy-IT&ha_sourceId=89000468

🔗 社区DFX专题文章: https://developer.huawei.com/consumer/cn/forum/subject/2101218731402391001?ha_source=zxqy-IT&ha_sourceId=89000468

【扫码加入 HarmonyOS DFX 技术交流群】





©本站发布的所有内容,包括但不限于文字、图片、音频、视频、图表、标志、标识、广告、商标、商号、域名、软件、程序等,除特别标明外,均来源于网络或用户投稿,版权归原作者或原出处所有。我们致力于保护原作者版权,若涉及版权问题,请及时联系我们进行处理。
分类
HarmonyOS
地址:北京市朝阳区北三环东路三元桥曙光西里甲1号第三置业A座1508室 电话:13391790444或(010)62178877
版权所有:电脑商情信息服务集团 北京赢邦策略咨询有限责任公司
声明:本媒体部分图片、文章来源于网络,版权归原作者所有,我司致力于保护作者版权,如有侵权,请与我司联系删除

京ICP备:2022009079号-2

京公网安备:11010502051901号

ICP证:京B2-20230255