本节摘要:性能优化的第一戒律是先测量后动手。本节讲透 DevTools 性能视图的读法:一帧的账记在 UI 线程与光栅线程两个本子上,卡顿必居其一;再配上性能叠加层这个日常仪表,让掉帧在开发期就现形。读完你将能把"感觉有点卡"翻译成"哪帧、哪线程、哪工序"的工程描述。
第 2 章的管线知识在此变现。一帧的账记在两个本子上:UI 线程负责构建与布局——执行你的 build、算约束树;光栅线程(Raster 线程)负责把绘制指令变成像素——合成与光栅化。两本账任何一本超了 16 毫秒预算,这一帧就掉。
归因口诀随此而来:UI 线程长,怪你的 Dart 代码——build 里做重活、布局嵌套爆炸、同步计算占道;光栅线程长,怪绘制指令量——图层太多、重绘范围太大、图片解码尺寸失当。这个二分法覆盖了九成卡顿的第一归因,DevTools 里两行帧条谁红了一眼便知。
DevTools 的打开方式有两种:运行中按终端提示的地址进浏览器版,或 IDE 内置面板。性能(Performance)页给的是帧级时间线——每一帧展开能看到构建、布局各自的耗时占比;内存(Memory)页看堆的增长曲线与对象统计;另有网络、调试等多页随用随开。本书只深用性能与内存两页,够覆盖日常。

DevTools 要连电脑看,日常开发时更方便的是性能叠加层——两幅实时柱状图直接叠在界面上,绿即健康、红即超预算,与两个线程一一对应:
MaterialApp( showPerformanceOverlay: true, // debug 期开着,像开车看转速表 // ... )
工作流因此固定:debug 期叠加层常开,随手滑动列表、切页面,柱状图飙红就当场停下来查;真机上量(模拟器的性能不可信,它跑在你的开发机上);Profile 模式下复测(debug 的 JIT 与断言有额外开销,Profile 模式接近发布性能,数字以此为准)。
把方法走一遍。现象:真机上账单列表快速滚动偶发掉帧。按流程来——
测量:叠加层可见滚动中光栅线程间歇飙红,UI 线程全程绿。归因口诀直接给出方向:绘制指令量问题,不怪 Dart 逻辑。定位:DevTools 性能页展开红帧,光栅耗时集中在一段"图层合成";页面上每条账单卡片带全圆角、渐变背景与一枚阴影,几百条滚下来,光栅线程在拼命算阴影边缘。
验证:把卡片阴影临时换成描边(一行改动),红帧消失——归因成立。权衡:阴影是设计要求,不能简单砍。最终方案:给列表项包 RepaintBoundary(滚出屏幕的行不参与重绘)并把渐变从每帧计算改为预烘焙图片,红帧归零,观感无损。
这个案例的完整意义不在结论而在路径:现象、测量、归因、验证、权衡——五步走完,每次优化都有据可查。没有测量的优化是玄学:凭感觉把 build 拆得稀碎、到处包 const,可能一分帧时间没省,代码可读性先赔进去了。
内存页的第一眼只看两件事:趋势与抖动。反复进出同一页面,内存基线阶梯式上升且不回落——泄漏信号,头号嫌疑是没释放的控制器、订阅与定时器(第 3 章的 dispose 纪律就是为这一刻准备的);一次性大图片加载导致的尖峰——图片降采样与缓存策略问题。普通业务应用不必深究每一次分配,抓趋势异常即可;图片类重灾区在下一节有专段。
轻记账踩过的一个真实泄漏可以当教材:账单页的搜索框监听了输入流,dispose 时忘了取消,退出页面后监听还在——每次重进都多挂一个监听,内存曲线每进一次涨一小格。定位手法就是上面的趋势观察:反复进出十次,曲线十级台阶,泄漏实锤;再用内存视图的对象统计按引用链回溯,两分钟找到那个没取消的订阅。内存问题在仪表盘上都是"看得见的形状",形状对上了再去对代码,比凭空猜快得多。
问:模拟器上顺滑,真机掉帧,信谁? 信真机。模拟器的图形走开发机的 GPU,CPU 也是桌面级,两侧都不代表手机的真实预算。所有性能结论以中低端真机为准——旗舰机的数据会给你虚假的安全感。
问:debug 模式不卡、发布版卡(或反过来),正常吗? 正常且常见。调试版的 JIT、断言与检查有额外开销,两边数字都不可直接比较;口径统一用 Profile 模式——它接近发布版的性能,又保留了仪表盘的可观测性。
问:掉一帧两帧要紧吗? 偶发掉帧(转场瞬间、首次加载)用户无感,不必追;持续掉帧(滚动中红条连成串)才需要开工。把精力花在"模式性"的掉帧上,别花在一次性成本上。
叠加层告诉你"红了",性能页的帧详情告诉你"谁干的"。点开一根红条,时间线按工序展开成一段火焰式的耗时条:构建段展开能看到每个被重建的组件名与耗时,布局段能看到约束传递的深度,光栅段能看到图层合并的成本。读帧详情的手法有两条:
先看占比再看绝对值。 一帧 34 毫秒,构建占 22 毫秒——八成问题在 build 里的某个重活;展开构建段按耗时排序,头部的组件名就是第一嫌疑人。别从上到下平均用力,耗时分布永远头重脚轻。
对照改动前后同一操作的帧详情。 单次数值意义有限,"同一操作、改动前后"的对照才有结论。轻记账的做法是把常用操作(进首页、滚动账单、打开统计)写进一份手测脚本,每次优化前后各跑一遍并截图存档——这份档案既是优化的验收单,也是给后来者的性能地图。
若嫌疑人指向"某组件总在重建",下一步不是瞎猜原因,而是用重建计数手段(DevTools 的重建统计或下一节的计数日志)确认触发源;若指向布局深嵌套,把该子树的结构画出来数层数,超过五层的组合就该考虑拍扁。仪表盘负责指路,具体修法是下一节的主菜。
仪表盘教会我们找病灶,下一节开工治病:重建、列表、图片、启动与包体积,逐一过堂。