2. 编译耗时分析工具:--profile 报告、Build Scan、Gradle Console 输出解读
编译提速的前提是准确测量耗时分布。Gradle 提供了三个互补的耗时分析工具:控制台实时输出、--profile 离线报告以及Build Scan 云端分析。它们分别适用于不同场景:快速定位单次构建瓶颈、持续跟踪历史趋势、团队共享分析结果。本章将逐一解析它们的原理、使用方法和解读技巧。
2.1 Gradle Console 实时输出解读
Gradle 默认控制台会输出每个 Task 的执行耗时。使用 --info 或 --debug 级别时,信息更详细;推荐在 CI 环境中使用 --console=plain 避免转义字符干扰。
关键输出行示例
> Task :app:compileKotlin 2.345s
> Task :data:compileKotlin 1.123s
> Task :app:lint 4.567s
BUILD SUCCESSFUL in 45.678s
39 actionable tasks: 39 executed
- Task 耗时:每行末尾的时间是任务的 Wall Clock Time(包含 I/O 等待)。
- BUILD SUCCESSFUL 总耗时:表示整个构建过程从开始到结束的墙钟时间。
- executed / up-to-date:揭示增量编译效果。
技巧:关注耗时超过 2 秒的任务,它们通常是优化重点。若某个 Task 标记为
UP-TO-DATE 但依然耗时,说明输入文件探测或缓存检查有开销。
2.2 --profile 离线报告
--profile 参数会在构建结束后生成一份 HTML 报告,位于 build/reports/profile/ 目录下。该报告以时间线和表格形式展示 Task、配置、依赖解析等阶段的耗时。
生成命令
./gradlew clean assembleDebug --profile
报告结构
| 报告章节 | 内容说明 | 典型优化点 |
|---|---|---|
| Summary | 总耗时、Task 数量、缓存命中数 | 缓存命中低 → 检查输入文件或禁用缓存 |
| Timeline | 任务执行时间线(甘特图) | 串行 Task 过长 → 并行化或任务合并 |
| Task Execution | 每个 Task 的耗时、CPU 时间、GC 时间 | 高 CPU 时间 → 代码优化;高 GC → JVM 参数调整 |
| Configuration | 构建脚本初始化耗时 | 超过 2 秒 → 减少 plugin apply 或使用生命周期钩子 |
| Dependency Resolution | 依赖解析耗时、仓库请求次数 | 请求过多 → 使用 --offline 或本地缓存 |
注意事项:
--profile 报告仅记录 进程内 耗时,不包含 Gradle daemon 启动时间。若需分析 daemon 启动,请使用 --no-daemon 后收集日志。
2.3 Build Scan 云端分析
Build Scan 是 Gradle Enterprise 提供的付费功能,但开源项目可通过 --scan 免费生成临时链接(有效期 30 天)。它比 --profile 更强大:支持历史对比、性能警告、Task 依赖可视化、缓存命中分析等。
生成命令
./gradlew clean build --scan
构建完成后控制台会输出一个唯一 URL,例如:https://gradle.com/s/abc123。点击即可访问。
关键功能
- Performance 标签页:自动标记低效 Task、过度序列化、高 GC 停顿。
- Timeline 标签页:支持放大/缩小,对比两次构建的耗时差异。
- 缓存分析:显示哪些 Task 从远端缓存命中,哪些因为输入变化而重新执行。
- Warning 列表:
Deprecated Gradle features、Configuration cache misses等。
适用场景:团队协作时,将 Build Scan 链接分享到 PR 或 CI 日志中,可快速定位构建变慢的原因。建议每次 CI 构建都启用
--scan 并归档链接。
2.4 三工具对比与选型
| 特性 | Gradle Console | --profile | Build Scan |
|---|---|---|---|
| 环境要求 | 无 | 无(本地文件) | 需网络(上传至服务器) |
| 粒度 | Task 级 | Task + 配置 + 依赖解析 | Task + 配置 + 依赖 + 缓存 + 警告 |
| 历史对比 | 不支持 | 手动对比文件 | 自动对比(需 Enterprise 订阅) |
| 推荐场景 | 日常快速排查 | 本地深入分析 | 团队协作与 CI 集成 |
2.5 各工具的数据流与关系
下图展示了三种工具在 Gradle 构建流程中的位置与数据流向。控制台实时输出来自 Gradle 工作进程;--profile 在构建结束后由 Gradle 主进程生成 HTML;Build Scan 则需额外上传到 Gradle Enterprise 服务器。
2.6 常见错误与调试
- --profile 报告未生成:检查是否有
rootProject.buildDir访问权限,或是否在子模块执行--profile(需在根项目执行)。 - Build Scan 上传失败:确认网络可访问
scan.gradle.com;若使用自托管 Gradle Enterprise,需配置gradle.properties中gradle.enterprise.url。 - 控制台时间与 --profile 不一致:控制台输出的是墙钟时间(含 JVM GC 停顿),--profile 提供的是线程 CPU 时间,两者可以相差 10%~30%。
调试建议:若某个 Task 在控制台显示 3 秒而在 --profile 中显示 0.5 秒 CPU 时间,说明该 Task 大部分时间花在 I/O 等待上(如网络依赖下载、文件锁竞争),应优先优化 I/O 路径。
2.7 性能优化应用
- 基于控制台:找到 Top 3 最具耗时 Task,检查是否能增量执行(开启
@CacheableTask注解)。 - 基于 --profile:关注 Configuration 阶段是否超过 5 秒,若是,使用
configuration-cache插件或懒加载allprojects块。 - 基于 Build Scan:利用 Warning 列表修复 Deprecated API,利用缓存分析调整
cacheStrategy配置。
// 示例:在 gradle.properties 启用配置缓存
org.gradle.unsafe.configuration-cache=true
通过 --profile 对比开启配置缓存前后的 Configuration 阶段耗时,通常能减少 50% 以上。
本章小结:掌握三种耗时分析工具的输出解读,是进行编译提速的第一步。建议在本地开发时日常使用控制台观察;在性能优化阶段使用 --profile 获取详细数据;在团队协作或 CI 中启用 Build Scan 建立性能基线。下一章将基于这些分析结果,讲解 Task 增量编译的具体配置与调优方法。