第2章 Gradle守护进程与配置缓存
2.1 原理概述
Gradle守护进程(Daemon)是一个长期运行的JVM进程,用于缓存构建元数据、类加载器、插件状态和项目配置信息。启用守护进程后,每次构建不再重新初始化整个Gradle运行时,而是复用已存在的进程,从而大幅缩短构建启动时间。
配置缓存(Configuration Cache)是Gradle 6.6+引入的优化技术。它将配置阶段的计算结果(Gradle对象图、Task依赖关系、属性值等)序列化到磁盘缓存中。当项目文件和构建逻辑未改变时,后续构建可以跳过整个配置阶段,直接从缓存反序列化配置结果,使配置耗时从秒级降至毫秒级。
守护进程与配置缓存协同工作:守护进程提供JVM的内存和类加载缓存,配置缓存提供磁盘级的配置结果快照。两者结合能将Android多模块项目的增量构建提速40%~60%。
关键指标:守护进程使构建启动时间减少70%以上;配置缓存使配置阶段耗时从2~5秒降至0.1~0.3秒(视项目规模而定)。
2.2 守护进程持久化配置
守护进程默认启用(Gradle 3.0+)。你可以通过以下方式显式控制其行为。
| 配置位置 | 参数 | 说明 |
|---|---|---|
gradle.properties | org.gradle.daemon=true | 开启守护进程(默认值) |
gradle.properties | org.gradle.daemon.idletimeout=600000 | 守护进程空闲超时(毫秒),默认10分钟。超时后自动停止以释放内存。 |
gradle.properties | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m | 为守护进程分配堆内存和元空间,避免OOM |
| 命令行 | --daemon / --no-daemon | 临时覆盖当前构建的守护进程策略 |
建议在~/.gradle/gradle.properties或项目根目录的gradle.properties中写入以下配置以实现守护进程持久化:
org.gradle.daemon=true
org.gradle.daemon.idletimeout=1800000 # 30分钟空闲超时
org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g
org.gradle.parallel=true
2.3 配置缓存开关配置
配置缓存通过Gradle属性或命令行启用。注意:配置缓存与某些插件(如自定义Transform、Kotlin MPP)存在兼容性问题,首次启用需仔细测试。
| 方式 | 配置内容 | 生效范围 |
|---|---|---|
| Gradle属性 | org.gradle.configuration-cache=true | 全局/项目级 |
| 命令行 | --configuration-cache | 单次构建 |
| 禁用缓存 | gradle --no-configuration-cache build | 单次构建 |
| 清理缓存 | gradle --configuration-cache rebuild | 清空并重新缓存(调试用) |
典型配置文件示例:
# gradle.properties(项目根目录)
org.gradle.configuration-cache=true
# 允许在配置缓存模式下使用Kotlin脚本(适配部分场景)
org.gradle.configuration-cache.internal.test-warning-log=true
# 最大缓存大小(默认200MB,大项目建议提升)
org.gradle.cache.size.max=1g
2.4 守护进程与配置缓存交互流程
理解核心流程:配置缓存只在守护进程中生效。首次构建仍须完整执行配置阶段,并将结果写入磁盘缓存;后续构建若项目文件未变,守护进程直接从缓存反序列化配置,跳过Task依赖解析和插件初始化。
2.5 常见冲突与解决
启用配置缓存后可能遇到以下冲突,需针对性处理:
| 问题 | 表现 | 解决方案 |
|---|---|---|
| 守护进程内存不足 | 构建失败:OutOfMemoryError: Metaspace |
增大JVM堆和元空间:-Xmx4g -XX:MaxMetaspaceSize=1g;同时减少空闲超时以释放资源。 |
| 配置缓存失效频繁 | 每次构建都重新配置,未命中缓存 | 检查buildSrc、自定义插件或Gradle版本是否修改;使用--configuration-cache rebuild强制清理重新缓存。 |
| Transform API或Kotlin KSP不兼容 | 构建报错:Configuration cache does not support Transform |
在gradle.properties中设置org.gradle.configuration-cache.internal.transform-compat=true(实验);或为相关模块关闭配置缓存。 |
| 多模块增量构建变慢 | Task输入/输出声明不完整导致缓存降级 | 检查Task的@InputFiles、@OutputDirectory等注解是否准确;使用--scan生成构建扫描分析缓存命中率。 |
| 守护进程版本不一致 | 多个Gradle版本的项目共用守护进程导致崩溃 | 每个项目使用独立的Gradle wrapper;在gradle.properties中设置org.gradle.daemon.idletimeout=0(不共享)。 |
调试建议:在发生配置缓存相关错误时,先使用
gradle --no-configuration-cache build确认是否为缓存问题。若构建正常,则逐步启用缓存并观察gradle/build/tmp/configuration-cache/report.html中的详细报告。
2.6 性能与稳定性优化
- 守护进程内存控制:为每个守护进程分配固定堆大小,避免因系统内存不足而频繁GC。推荐值为
-Xmx4g -XX:MaxMetaspaceSize=1g(根据项目模块数调整)。 - 配置缓存预热:CI场景下首次构建后保留缓存目录(
.gradle/configuration-cache),避免每次CI都重复配置。 - 构建并行度:配合
org.gradle.parallel=true,配置缓存与并行Task同时生效,最大化CPU利用率。 - 分级清理策略:定期清理过大的守护进程缓存和配置缓存,防止磁盘占用膨胀。使用
gradle --stop停止所有守护进程,手动删除~/.gradle/caches下的历史缓存。
2.7 验证与部署
在本地开发环境验证守护进程和配置缓存是否生效:
# 查看守护进程状态
gradle --status
# 第一次构建(记录耗时)
gradle clean assembleDebug --no-configuration-cache
# 第二次构建(启用配置缓存,观测配置阶段耗时)
gradle assembleDebug --configuration-cache
# 输出对比:配置阶段时间应明显缩短
在CI环境中推荐显式启用:
# 在CI的gradle.properties中
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.configuration-cache=true
org.gradle.caching=true
org.gradle.vfs.watch=true # 文件系统观察者(提高文件变化检测速度)
注意:部分CI平台(如Jenkins)默认禁用守护进程,需在启动命令后追加--daemon。同时确保CI工作目录的~/.gradle具有持久化存储,否则每次构建都会重建守护进程和配置缓存。