3. Gradle内置性能分析工具简介
做Gradle性能优化,第一件事是搞清楚问题在哪。我个人习惯先不开任何第三方插件,就用Gradle自己带的那几个工具。为什么呢?因为内置工具零配置、零依赖,而且给出的数据足够精确。你想想看,如果连内置工具都不熟,贸然上外部方案,很容易踩坑。
我记得刚开始带团队时,有个同事一上来就加了一堆分析插件,结果构建反而更慢了。后来我们回头用Gradle原生的 --profile 参数,十分钟就找到了瓶颈。嗯,所以这节课我们先把这三个「贴身侍卫」搞清楚。
3.1 三个最常用的内置工具
Gradle自带了三个性能分析手段:命令行参数、构建扫描、缓存统计。它们覆盖了从黑盒到白盒、从本地到远程的各个层面。
- --profile:生成HTML报告,按阶段拆分耗时。
- --scan:上传构建数据到Gradle Cloud,可视化全链路。
- --build-cache-stats:查看缓存命中率,评估缓存价值。
--profile 做本地快速诊断,发现可疑点再用 --scan 深挖。缓存统计则在调整缓存策略前后必跑一次。
3.2 逐一拆解:用法与输出
3.2.1 --profile 参数
用法就一行命令:
./gradlew assembleDebug --profile
运行后,在 build/reports/profile/ 目录下会生成一个HTML文件。打开它,你会看到四个核心指标:
- Total Build Time:总耗时。
- Task Execution:每个任务的耗时。
- Configuration:配置阶段耗时。
- Dependency Resolution:依赖解析耗时。
我记得第一次用它时,发现有个自定义任务竟然占了总时间的40%。你猜怎么着?那个任务里写了个无意义的 Thread.sleep(1000)。所以说,别凭感觉猜,数据说话。
3.2.2 构建扫描 (Build Scan)
构建扫描更直观。执行:
./gradlew assembleDebug --scan
命令结束后,Gradle会输出一个链接,类似 https://scans.gradle.com/s/xxxxx。点开它,你会看到一个网页版的仪表盘,包含:
- 任务耗时瀑布图(就是后面章节要讲的瀑布图雏形)。
- 依赖树及其版本冲突。
- 构建缓存命中详情。
- 插件和脚本配置时间。
3.2.3 构建缓存统计
这个工具比较冷门,但非常实用。执行:
./gradlew --build-cache-stats
输出类似:
Cache location: /Users/me/.gradle/caches/build-cache-1
Pack hits: 234
Pack misses: 12
Store requests: 89
Hit rate: 95.1%
命中率低于50%就得检查了,可能是缓存key设计不合理,或者跨机器环境不一致。
3.3 如何选择工具?一个对比表格
| 工具 | 输出形式 | 适用场景 | 我的评分 |
|---|---|---|---|
| --profile | 本地HTML报告 | 快速定位任务级瓶颈 | ★★★★★ |
| --scan | Web仪表盘 | 全链路可视化、团队共享 | ★★★★☆ |
| --build-cache-stats | 命令行文本 | 评估缓存效果、排查缓存失效 | ★★★☆☆ |
我个人的优先级:先 --profile 扫一遍,如果发现配置阶段或依赖解析异常,再上 --scan 看细节。缓存统计我一般写在CI脚本里,每次构建后自动输出命中率。
3.4 核心关系图:内置工具家族
下面这张图总结了三个工具在分析流程中的位置和关系。注意看箭头方向——它们是互补的,不是替代关系。
核心结论:三个工具覆盖了「构建命令 → 原始数据 → 分析维度 → 决策输出」这一完整链路。你想要定位具体任务慢,看--profile;想要全局视角和团队协作,看--scan;想要评估缓存收益,看--build-cache-stats。
3.5 我踩过的两个坑
- 坑一: 跑
--profile时忘了关并行执行,导致报告里任务耗时交叉,很难判断真正的串行依赖。后来我习惯先加--no-parallel跑一次基准。 - 坑二: 构建扫描默认会跳过缓存未命中的详细信息。如果你发现缓存命中率低,记得加
-Dscan.capture-tasks=true得到完整日志。我曾经因为没加这个参数,花了一天排查缓存为什么没命中央,结果发现是机器时区不同……
--scan。每个扫描都会生成一个永久链接,信息泄漏风险不可忽视。至少要在Gradle Enterprise中配置访问权限。