鸿蒙小助手 2026-10-21 14:27:43 发布本原创文章帖发布在华为开发者联盟社区,欢迎开发者前往访问评论交流,更多与该内容相关讨论,请点击原帖查看:
Flutter 性能调优之性能分析工具与 trace 介绍-华为开发者话题 | 华为开发者联盟
Flutter 应用在鸿蒙(OpenHarmony)平台上的性能问题,通常表现为滑动卡顿、点击无反馈、页面加载迟缓等现象。定位这些问题需要理解 Flutter 的渲染流程与线程模型,并掌握 DevEco Studio Profiler 与 Flutter DevTools 两类工具的 trace 采集与解读方法。
本文是 Flutter 鸿蒙性能定位系列的基础篇,介绍 Flutter 的渲染流程、线程模型、关键 trace 点以及两类性能分析工具的使用方法,为后续具体场景问题的定位提供基础。完成本文阅读后,如需深入定位具体问题,请继续阅读:
1. 前置条件
• HarmonyOS 系统(5.0及以上版本),前台运行 Flutter 页面;
• 分析工具:
本文截图使用的 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 | 应用主线程 |
| 触摸事件投递至 Flutter | H:flutter::Shell::OnPlatformViewDispatchPointerDataPacket | 应用主线程 |
| Flutter UI 线程收到触摸事件 | H:flutter::Engine::DispatchPointerDataPacket | ui |
| 请求新一帧绘制 | H:flutter::Animator::RequestFrame | ui |
| 开始一帧绘制,生成图层树 | H:flutter::Animator::BeginFrame frame_number: | ui |
| 将图层树转为 GPU 指令并光栅化 | H:flutter::GPURasterizer::Draw | raster |
| RenderService 合成各节点图层 | H:RSMainThread::DoComposition | render_service |
| GPU 执行最终绘制 | H:RenderFrame | RSUniRenderThread |
说明: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 性能调优之点击响应和完成时延介绍 (系列第三篇)
DevEco Studio Profiler 调优工具介绍
Flutter DevTools 调优介绍
----------------------------------------------------------------------------------------------------------

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


【扫码加入 HarmonyOS DFX 技术交流群】
相关推荐
鸿蒙小助手
25
0
鸿蒙小助手
35
0
KevinChaos
122
0
KevinChaos
119
0
鸿蒙小助手
致力于为鸿蒙开发者谋福利
帖子
提问
粉丝
Flutter 性能调优之页面滑动卡顿问题介绍
2026-10-21 14:20:05 发布Flutter 性能调优之点击响应和完成时延分析介绍
2026-10-21 14:13:01 发布


京公网安备:11010502051901号