中低端真机上一滑就顿——同一段列表动效,调试构建在模拟器上偶尔掉一下帧,也不刺眼。换到用户那类机器,滑动轨迹开始肉眼可见。有人让开 Performance Overlay,屏幕上叠出上下两张小图,竖条一红,又不知道先查 Dart 还是先砍绘制。
Flutter 官方性能页把前置条件写得很死,下面按文档对齐,不把社区观测写成引擎承诺。
先满足:真机 + profile
UI performance 开头就强调:几乎所有 Flutter UI 性能调试都应在实体 Android / iOS 设备上,并以 profile 模式跑应用。调试模式,或在模拟器、仿真器上跑的表现,通常代表不了正式包。
原因也很明白:模拟器和真机硬件路径不同,有的操作更快、有的更慢。debug 会开断言等额外检查,本身就贵。debug 走 JIT,profile / release 是 AOT,JIT 编译停顿自己就能造成卡顿假象。命令行常用 flutter run --profile。IDE 里也有对应的 Profile 运行项。文档还提醒:Overlay 也要在 profile 下看,debug 下的图容易误导。
目标帧率按页上的说法,常见是 60 fps(约每帧 16ms),支持更高刷新率的设备可以到 120。超时的帧会被丢掉,动画就抖。
Overlay 上下两条各代表什么
官方说明:Performance Overlay 由引擎绘制,不是普通 Widget,对性能影响尽量小。图上是最近约 300 帧。
- 上面那条(图里标成 GPU 图)对应 Raster 线程:把 UI 线程交过来的 layer tree 栅格化,并和 GPU 打交道。Skia / Impeller 跑在这条线上。注意:栅格化是为 GPU 做的,但 Raster 线程本身在 CPU 上跑。
- 下面那条对应 UI 线程:你的 Dart 和框架代码在这里执行,负责建 layer tree,再送给 Raster。
白色横线大致是 16ms 刻度。图往上越过这条线,就意味着撑不住 60Hz。某一帧在任一图里超时,会出现竖着的红条。文档原意是:
- UI 图出现红条:Dart 侧太贵,先查自己的代码路径(重建、布局、同步计算等)。
- GPU / Raster 图出现红条:场景对栅格化太重。
两边都红时,文档建议先诊断 UI 线程。空闲时应用不画帧,图会停住,这是正常现象。
开关方式页上也写了:DevTools Performance 视图一键、命令行里按 P、或按调试文档程序化打开 Overlay。需要逐帧时间线时,再用 DevTools 的 Performance / Timeline,别只盯两张条形图猜。
Raster 红了常见往哪抠
UI 图干净、Raster 图却红,说明 layer tree 可能很好建,但绘制贵。文档点名几类重活:不必要的 saveLayer、透明度与多对象交叉、特定情形下的裁剪和阴影。saveLayer 被写成框架里最贵的方法之一。即使你没手写调用,Clip.antiAliasWithSaveLayer 这类 clipBehavior 也可能间接触发。
自问三句就够用:这个效果还要不要。调用能不能删掉。能不能把透明度/裁剪/阴影落到单个子节点,而不是罩在整棵子树上。动画全程都慢时,可对照页里 Slow Animations。静态场景被旋转淡入拖慢时,文档提到 RepaintBoundary 等缓存思路——只在确实需要时用,栅格缓存本身也占 GPU 内存。
关于渲染后端:同站 Impeller 介绍里写,较新版本上 Impeller 已是 iOS 以及 Android API 29+ 的默认引擎之一,目标包括更可预期的着色器编译和必要时把单帧工作分散到多线程。排查卡顿时仍以 Overlay / Timeline 现象为准。换引擎或开关旗标属于另一条线,这篇不展开。
「八核机器 Raster 只跑两核」怎么理解
有用户在真机上观察到:即便 SoC 标称很多核,Raster 相关负载仍像挤在少数核上。这是用户侧观测,不是 Flutter 性能页里的官方结论,也别写成「引擎只用两核」的产品承诺。若怀疑调度或后端差异,用 DevTools 导出时间线、记下机型和芯片信息,对照具体帧里 UI 与 Raster 各自的耗时,比先下绑核结论更有用。
你们卡顿时是只有 Raster 红,还是 UI 一起红?有没有在最慢的那档真机、profile 下复现过同一条操作路径?