第2章 Gradle守护进程与构建缓存优化
Gradle 守护进程与构建缓存是 Android 构建加速的“双引擎”。守护进程避免 JVM 冷启动与类加载开销,构建缓存复用历史输出,增量编译只重编译变更文件。本章围绕原理、参数调优、缓存策略和增量编译实现展开,并提供可复现的配置命令与调试方法。
2.1 守护进程参数调优
守护进程是可复用的后台 Gradle 运行时。核心调优点是 JVM 堆内存、生存策略和并行工人数。
| 参数 | 作用 | 建议值 |
|---|---|---|
org.gradle.jvmargs | 守护进程 JVM 参数(堆、GC) | -Xmx2048m -XX:MaxMetaspaceSize=512m |
org.gradle.parallel | 并行执行任务 | true |
org.gradle.daemon.keepalive | 闲置超时(分钟) | 30 |
org.gradle.caching | 启用构建缓存 | true |
典型
gradle.properties 配置:org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.parallel=true
org.gradle.daemon.keepalive=30
org.gradle.caching=true
堆内存建议:物理内存的 50%~70% 分配给守护进程,但不超过 4GB(AGP 常规场景)。HeapDumpOnOutOfMemoryError 可辅助定位 OOM 原因。
2.2 构建缓存策略配置
构建缓存包括本地缓存(~/.gradle/caches/build-cache-1)和远程缓存(HTTP 服务)。缓存键由任务输入(文件、属性、类路径等)的哈希组成。
| 类型 | 存储位置 | 适用场景 |
|---|---|---|
| 本地缓存 | 用户目录 | 单人开发、本地构建加速 |
| 远程缓存 | HTTP 服务器(如 Redis、S3) | CI/CD、团队共享构建输出 |
在 settings.gradle.kts 或 settings.gradle 中配置:
// settings.gradle.kts
buildCache {
local {
isEnabled = true
directory = File(rootDir, ".build-cache")
removeUnusedEntriesAfterDays = 7
}
remote {
isEnabled = true
url = uri("https://build-cache.example.com/cache/")
isPush = true
credentials {
username = "cacheUser"
password = System.getenv("CACHE_PASSWORD")
}
}
}
缓存键冲突:若远程缓存地址不可达或认证失败,Gradle 会静默降级为本地缓存。确保 CI 环境能正常推送和读取缓存,否则可能造成缓存污染或命中率下降。
2.3 增量编译原理
增量编译指只编译自上次构建以来发生变更的源文件或模块。Java 使用 compileAvoidance(ABI 分析),Kotlin 使用增量编译标记。核心决策流程:
- Gradle 对每个编译任务计算输入快照(文件内容哈希、类路径哈希)。
- 若任务未命中构建缓存,则检查增量编译标记文件(如
.gradle/7.5/compileJava/incremental)。 - 根据文件时间戳或哈希差异,筛选出变更的源文件。
- 仅对变更文件及其直接依赖文件(受类型层次影响)执行编译。
- 输出新的类文件,更新增量标记。
若增量编译不可用(如注解处理器、KAPT、大量接口变更),Gradle 会回退到全量编译。
通过
--info 日志可查看增量编译决策:Task ':app:compileDebugKotlin' is not up-to-date. Reason: Input file ... has changed.2.4 调试与诊断
使用以下命令查看守护进程状态和构建缓存命中率:
# 查看所有运行中的守护进程
gradle --status
# 强制停止守护进程(调试参数变更是需要)
gradle --stop
# 开启详细日志观察缓存行为
gradle assembleDebug --info 2>&1 | grep -i "cache\|incremental"
# 查询本地缓存利用率
ls -lh ~/.gradle/caches/build-cache-1/*.bin | wc -l
在 build/scans/ 目录生成构建扫描报告(需启用了 --scan 或 com.gradle.enterprise 插件),可图形化查看缓存命中与增量编译决策。
缓存命中率公式:
命中次数 / (命中次数 + 未命中次数)。通常 CI 环境应达到 > 70%,本地开发 > 50% 为健康。2.5 常见错误与优化实践
- 守护进程 OOM:调整
-Xmx,或使用-XX:+UseContainerSupport(容器环境)。 - 缓存未被命中:检查任务输入是否包含路径、时间戳或不稳定插件。使用
--info查看Cache key ...的组成。 - 增量编译失效:KAPT 或自定义注解处理器强制全量编译。可尝试开启
kotlin.incremental.useClasspathSnapshot=true(实验性)。 - 守护进程启动缓慢:避免同时启动多个守护进程的堆内存超过物理内存。设置
org.gradle.jvmargs中-Xms与-Xmx相同以减少动态扩展。 - 远程缓存认证失败:在 CI 日志中搜索
HttpBuildCache: could not store entry,确认CACHE_USER和CACHE_PASSWORD环境变量是否正确注入。
通用优化清单:① 保证
org.gradle.parallel、org.gradle.caching、org.gradle.daemon 均为 true;② 远程缓存使用 isPush = true 仅对 CI agent 开启;③ ~/.gradle/gradle.properties 中统一守护进程参数以避免项目覆盖。