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。点开它,你会看到一个网页版的仪表盘,包含:

  • 任务耗时瀑布图(就是后面章节要讲的瀑布图雏形)。
  • 依赖树及其版本冲突。
  • 构建缓存命中详情。
  • 插件和脚本配置时间。
注意:默认情况下,构建扫描会上传到Gradle的公共服务器。如果你的项目涉及敏感信息,建议配置私有构建扫描服务器或在CI中禁用上传。我曾经有个甲方项目,把内网路径暴露了,还好及时发现撤回了扫描。

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 核心关系图:内置工具家族

下面这张图总结了三个工具在分析流程中的位置和关系。注意看箭头方向——它们是互补的,不是替代关系。

Gradle 内置性能分析工具家族 ./gradlew assembleDebug --profile 本地HTML报告 --scan Web仪表盘 --build-cache-stats 命令行统计 任务级耗时 配置/执行/依赖 全链路可视化 瀑布图/依赖树/缓存 缓存命中率 hit/miss/存储 使用建议 先profile快速定位 → 再scan深入分析 缓存统计放在CI中持续监控

核心结论:三个工具覆盖了「构建命令 → 原始数据 → 分析维度 → 决策输出」这一完整链路。你想要定位具体任务慢,看--profile;想要全局视角和团队协作,看--scan;想要评估缓存收益,看--build-cache-stats。

3.5 我踩过的两个坑

  • 坑一: 跑 --profile 时忘了关并行执行,导致报告里任务耗时交叉,很难判断真正的串行依赖。后来我习惯先加 --no-parallel 跑一次基准。
  • 坑二: 构建扫描默认会跳过缓存未命中的详细信息。如果你发现缓存命中率低,记得加 -Dscan.capture-tasks=true 得到完整日志。我曾经因为没加这个参数,花了一天排查缓存为什么没命中央,结果发现是机器时区不同……
警告:不要在正式CI流水线上不加控制地使用 --scan。每个扫描都会生成一个永久链接,信息泄漏风险不可忽视。至少要在Gradle Enterprise中配置访问权限。