4、瀑布图(Flame Chart / Waterfall)基础概念
说实话,我刚接触构建性能分析那会儿,看到一堆花花绿绿的条条框框,头都是大的。什么火焰图、瀑布图、调用树——听着就晕。但后来我发现,只要搞懂其中一种,其他就能触类旁通。今天咱们就聊聊瀑布图(Waterfall),它在AGP版本升级和缓存瓶颈定位里,几乎是必用的工具。
4.1 什么是瀑布图?
瀑布图,也叫时序瀑布图,本质上是一张时间轴展开的任务执行记录。每一条横条代表一个任务(比如编译一个模块、执行一次AAPT2、运行一次DexBuilder),横条的长度表示它耗时多久,横条的排列顺序就是任务的执行顺序。
你可以想象一下:从构建开始到结束,所有任务像瀑布一样从上往下流淌。每个任务都会在它对应的时刻开始,然后结束。如果某个任务特别长,或者两个任务本该并行却串行了,一眼就能看出来。
我个人习惯把瀑布图叫做「构建过程的X光片」——它把那些看不见的「慢点」赤裸裸地曝光出来。
4.2 瀑布图 vs 火焰图:别搞混了
你可能还听说过火焰图(Flame Chart)。很多新手会把这两者搞混,我刚开始学的时候也踩过坑。这里给你一张对比表,我建议你直接收藏:
| 维度 | 瀑布图(Waterfall) | 火焰图(Flame Chart) |
|---|---|---|
| 关注点 | 任务的执行时序与耗时 | 调用栈的深度与热区 |
| 横轴 | 时间 | 采样次数 / 耗时占比 |
| 纵轴 | 任务 ID 或线程 | 调用栈层级(越往上越底层) |
| 典型用途 | 定位串行阻塞、缓存失效、资源等待 | 定位热点函数、CPU 占用、算法瓶颈 |
| AGP 升级场景 | 非常有用,能看出哪个任务拖慢了整体 | 较少直接使用,适合分析编译内部 hook |
说白了,瀑布图回答「哪里等得久」,火焰图回答「哪里算得久」。在AGP版本升级和缓存失效排查中,我们更关心「时间线上的等待」,所以瀑布图是主角。
4.3 瀑布图的核心构成要素
要读懂瀑布图,你得先认识它的几个基本元素。下面这张图我手绘了一个简化版,你可以对照着看:
从上图你能看到几个关键点:
- 横条长度 = 任务耗时,越长越可疑。
- 横条重叠 = 并行执行,理想情况。
- 横条首尾相接 = 强制串行,可能因为依赖关系或全局锁。
- 红色或橙色横条(在我常用的工具里)往往标注出异常耗时。
4.4 瀑布图的常见数据来源
在Android构建领域,你能拿到瀑布图的地方主要有三个:
- Android Studio Build Analyzer —— 最方便,直接在IDE里就能看。AGP 7.0以上自带。
- Gradle Profiler —— 命令行工具,输出JSON/HTML报告,适合CI环境自动化采集。
- Build Scan(Gradle Enterprise) —— 企业版,带时序视图,但需要付费。
我个人偏爱Build Analyzer,因为操作简单。但你如果做自动化对比,Gradle Profiler更合适。
--profile 或 --scan 单独分析。
4.5 如何从瀑布图里找到缓存瓶颈?
好,理论讲完了,咱们来点实战的。假设你刚升级完AGP,发现构建时间没降反升。打开瀑布图,你应该优先找这几种「危险信号」:
4.5.1 信号一:连续很多个「满长度」的任务
你看,正常缓存命中时,像 compileDebugJavaWithJavac 这类任务应该只有几百毫秒。但如果它每次都是好几秒——说明增量编译失效了。我遇到过一回,发现是因为AGP 8.0把某些注解处理器的incremental选项改成了默认关闭,需要手动开启。
4.5.2 信号二:多个任务之间出现大段空白
如果两张横条之间有一段「空窗期」(没有任务在跑),那很可能是等待I/O或者外部资源。比如,一些自定义Transform任务会写文件到磁盘,如果同时还有别的任务也在写同一块目录,就会互相等待。这种在瀑布图上表现为一条条空档。
4.5.3 信号三:某个任务反复出现「突变」
你连续跑两次同样的构建,对比瀑布图。如果某个任务前一次耗时0.5秒,后一次变成5秒——那就是缓存被清了。我曾经碰到过,因为某插件在clean阶段偷偷删了build/cache目录,导致整个缓存失效。查了一天才找到。
4.6 实操:5分钟导出你的第一张瀑布图
我建议你现在就动手试一下。步骤如下:
- 在Android Studio中打开你的项目。
- 点击菜单栏
Build → Build Analyzer。 - 点击
Run Build,等待一次完整的assembleDebug执行完毕。 - 在打开的Build Analyzer界面里,选择 Timeline 标签页。
- 你就看到了真·瀑布图。
这时你可以用鼠标拖动、缩放,把所有任务摊开。重点看:
compile相关的任务是否耗时异常?mergeResources、processResources是不是每次都在重新生成?- 有没有某些任务被标记为
UP-TO-DATE但实际却跑了?(这是一个常见的Gradle缓存bug)
如果发现某些任务的耗时超过了你的预期,别急——下一节我们会专门讲怎么拆解这些长耗时任务,看看问题到底出在CPU、I/O还是锁竞争上。
嗯,瀑布图这东西,第一次看可能觉得眼花。但相信我,多用几次,你就能一秒揪出「谁在摸鱼」。它是AGP升级之旅当中,你最值得信赖的伙伴之一。