Gradle 依赖反复下载?缓存回收与排查指南
背景
不少 Android / Java 开发者遇到过这个现象:一个 Gradle 项目,之前正常打开过、依赖都下载好了,过了一两周甚至一个月重新打开 Android Studio 或者执行 ./gradlew build,Gradle 又开始从头下载所有依赖了。
这不是错觉,也不是 Gradle 的 bug。背后有几层原因,下面逐个拆解。
原因一:Gradle 缓存 GC(最常见)
Gradle 内置了缓存自动清理机制。默认每 7 天 检查一次,删除 24 小时内未被访问 的缓存条目。
也就是说,如果你两周没碰项目,Gradle Daemon 也没运行,那么整个 ~/.gradle/caches/modules-2/ 里的依赖 Jar 包都会被判定为”已过期”,在下次构建时被当作无效缓存清理掉。下次构建就只能全部重下。
检查方法
cat ~/.gradle/caches/gc.properties注意:
gc.properties只在 Gradle 执行过缓存 GC 后才会生成。如果你从未遇到过依赖重下的问题,这个文件可能根本不存在,这不代表 GC 没在工作——说明你的缓存一直在被活跃使用,从未触发过清理。
如果看到 last-gc-timestamp 在几天前,且你的项目在间隔期内没打开过,那就基本实锤了。
解决方案
在项目或全局的 gradle.properties 中调整:
# 方案 A:完全禁用缓存 GC(推荐)gradle.cache.cleanup.enabled=false
# 方案 B:延长保留天数gradle.cache.cleanup.retain.unused.days=30原因二:Gradle Wrapper 版本变化
现在很多项目通过 Gradle Wrapper 锁版本。但如果:
- 项目接入了 Renovate / Dependabot 自动更新 Wrapper 版本
- 同事提交了升级 Wrapper 的 commit(
./gradlew wrapper --gradle-version=8.x) - 之前是 8.7,后来自动升级到了 8.9
那整个 Gradle 发行版都要重新下载,而且新版本 Gradle 的缓存路径不同,已有的 ~/.gradle/caches/ 对不上,就相当于所有依赖也要重新解析和下载。
检查方法
cat gradle/wrapper/gradle-wrapper.properties看 distributionUrl 是否和上次构建时一致。
解决方案
如果是自动升级导致的,可以锁定 Wrapper 版本:
./gradlew wrapper --gradle-version=8.7然后在项目中提交 gradle/wrapper/gradle-wrapper.properties 的变更即可。
原因三:~/.gradle 目录被系统清理
Arch Linux(或者用 systemd-tmpfiles 的发行版)每天会按策略清理用户缓存目录。
检查自己的环境:
cat ~/.gradle/caches/gc.properties 2>/dev/null || echo "文件不存在(GC 未触发,但可以看 modules-2 体积判断)"du -sh ~/.gradle/caches/modules-2/如果 modules-2/ 的大小从几个 GB 变成了几十 MB,那肯定是被清理过了。
排查是否被 tmpfiles 清理:
grep -r "gradle" /usr/lib/tmpfiles.d/ /etc/tmpfiles.d/如果确实有相关配置,可以在 ~/.config/systemd/user/tmpfiles.d/ 里覆盖。不过更多情况下这只是人为误操作(比如清理磁盘时删了 ~/.gradle)。
原因四:依赖元数据过期
Gradle 在判断依赖是否需要重新下载时,会对比 Maven 仓库返回的 POM / module 文件的 Last-Modified 时间戳。如果远端仓库返回了比本地缓存更新的时间戳(即使内容没变),Gradle 也会认为缓存失效,触发重新下载。
这在用自建 Maven 仓库(如 Nexus、Artifactory)时比较常见,因为某些配置不当的代理仓库会对所有请求都返回最新的时间戳。
排查方法
开启 Gradle 的 info 日志:
./gradlew build --info 2>&1 | grep -i "caching\|downloading\|expired"如果看到大量 “Cached resource is expired” 的日志,说明是元数据过期问题。
解决方案
- 检查 Maven 仓库的缓存策略,确保 POM 的
Last-Modified稳定 - 或在 Gradle 中配置
cacheChangingModulesFor(0, 'seconds')来控制动态模块的缓存时长
完整排查流程
# 1. 确认缓存目录现状du -sh ~/.gradle/caches/modules-2/
# 2. 查看 GC 日志(如果文件不存在说明 GC 从未触发过)cat ~/.gradle/caches/gc.properties 2>/dev/null || echo "文件不存在,GC 尚未触发"
# 3. 检查 GRADLE_USER_HOME 是否被 IDE 改变echo $GRADLE_USER_HOME
# 4. 看 Wrapper 版本有没有变过git diff HEAD -- gradle/wrapper/gradle-wrapper.properties
# 5. 运行一次构建并查看缓存命中情况./gradlew dependencies --console=verbose总结
| 原因 | 概率 | 一句话判断 |
|---|---|---|
| 缓存 GC | ★★★★★ | gc.properties 有近期清理记录 |
| Wrapper 版本变了 | ★★★★ | distributionUrl 变了 |
| 系统清缓存 | ★★★ | ~/.gradle 体积明显变小 |
| 元数据过期 | ★★ | --info 日志显示大量 expired |
大部分情况下,在 gradle.properties 加上 gradle.cache.cleanup.enabled=false 就能解决问题。如果不想全局关闭 GC,设置 gradle.cache.cleanup.retain.unused.days=30 给一个更长的保留窗口也是个折中的选择。
欢迎关注我的公众号
如果这篇文章对你有帮助,欢迎扫码关注公众号,后续会继续分享技术实践、踩坑记录和效率工具。

支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!



