Gradle性能调优:让构建飞起来
说实话,Gradle慢起来真的让人抓狂。我见过不少团队,每天光等构建就要浪费半小时。我自己也踩过不少坑,今天就把这些经验分享给你。
Gradle性能调优,说白了就是三件事:让JVM更聪明、让并行更高效、别写烂代码。我们一个一个说。
核心思路:Gradle构建慢,90%的原因是你没给它合适的运行环境,或者脚本写得有问题。调优不是玄学,是有章可循的。
一、JVM参数调优:给Gradle配个好引擎
Gradle跑在JVM上,JVM的参数直接影响构建速度。我习惯在gradle.properties里配置这些参数:
# gradle.properties
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
几个关键参数:
-Xmx:最大堆内存。项目越大,这个值要越高。我个人建议至少2GB,大型项目可以给到4GB甚至8GB。-XX:MaxMetaspaceSize:元空间大小。Gradle会加载很多类,这个值太小容易OOM。-XX:+HeapDumpOnOutOfMemoryError:内存溢出时自动dump堆,方便排查问题。
小技巧:如果你不确定该设多大,可以先给4GB,然后观察构建时的内存使用情况。用jstat或者Android Studio的Profiler都能看。
我曾经遇到一个项目,构建总是莫名其妙地卡死。查了半天,发现是-Xmx设得太小,Gradle频繁触发Full GC。调大之后,构建时间直接缩短了40%。
二、守护进程配置:别让Gradle每次都从头来
Gradle守护进程(Daemon)是个好东西。它会在后台保持一个JVM进程,避免每次构建都重新加载类和配置。
默认情况下,守护进程是开启的。但有些团队会把它关掉,理由是「怕占用内存」。嗯,这里要注意:关掉守护进程,每次构建都要多花10-20秒的启动时间。
# 开启守护进程(默认就是true)
org.gradle.daemon=true
# 设置守护进程的超时时间(单位:毫秒)
org.gradle.daemon.idletimeout=3600000 # 1小时无操作后自动关闭
注意:如果你在CI/CD环境里构建,建议把超时时间设短一些,比如10分钟。否则构建机上的守护进程会一直占着内存。
我个人习惯在本地开发时保持守护进程常驻。你想想看,一天要构建几十次,每次省10秒,一天就能省下好几分钟。
三、并行编译:让CPU满负荷工作
现在的电脑都是多核的,但Gradle默认是单线程编译。这太浪费了。我们可以开启并行编译:
# gradle.properties
org.gradle.parallel=true
org.gradle.workers.max=4 # 根据你的CPU核心数调整
workers.max建议设为CPU核心数减1。比如你的是8核CPU,就设7。留一个核心给系统和其他应用。
我记得有一次给一个大型项目做优化,开启并行编译后,构建时间从12分钟降到了7分钟。效果立竿见影。
四、文件系统监控:别让Gradle瞎扫描
Gradle需要知道哪些文件变了,才能决定要不要重新编译。默认它会扫描整个项目目录。如果你的项目里有很多不需要监控的文件(比如build/、.git/、node_modules/),那扫描就会很慢。
解决方案是配置file.watch:
# gradle.properties
org.gradle.vfs.watch=true
org.gradle.caching=true
同时,在.gitignore里排除掉不需要监控的目录:
# .gitignore
/build
/.gradle
/local.properties
经验之谈:如果你用的是macOS,文件系统监控默认是开启的。但Windows和Linux上可能需要手动配置。我建议在gradle.properties里显式声明,避免不同环境行为不一致。
五、避免常见性能陷阱
这部分是我最想说的。很多性能问题,其实都是脚本写得不好导致的。
陷阱1:滥用allprojects和subprojects
很多人喜欢在根项目的build.gradle里写:
subprojects {
apply plugin: 'com.android.library'
android {
compileSdk 34
}
}
这样做的问题是:每个子项目都会执行这段配置。如果你的项目有20个模块,那这段代码就要执行20次。而且,有些模块可能根本不需要这些配置。
我建议改成按需配置:
// 只在需要的模块里单独配置
// 或者用条件判断
subprojects { subproject ->
if (subproject.name.startsWith('library-')) {
apply plugin: 'com.android.library'
}
}
陷阱2:在配置阶段执行耗时操作
Gradle的构建分三个阶段:初始化、配置、执行。配置阶段应该只做声明,不要做实际的计算或IO操作。
我曾经见过有人这么写:
// ❌ 错误示范:配置阶段执行网络请求
def version = new URL("http://api.example.com/version").text
android {
defaultConfig {
versionName version
}
}
每次执行gradle tasks都要等网络请求完成,太慢了。正确的做法是:
// ✅ 正确做法:延迟到执行阶段
android {
defaultConfig {
versionName project.findProperty("versionName") ?: "1.0.0"
}
}
陷阱3:不必要的依赖解析
Gradle每次构建都会解析依赖。如果你有很多动态版本(比如1.+),那每次都要去远程仓库查最新版本,非常慢。
我建议:
- 尽量使用固定版本号,比如
1.2.3而不是1.+ - 开启依赖缓存:
org.gradle.caching=true - 使用
--offline参数离线构建(如果依赖没变的话)
陷阱4:Task配置不当
有些Task默认会执行很多不必要的操作。比如lint,如果你不需要代码检查,可以跳过:
// 在gradle.properties里
android.enableLint=false
或者只在CI环境里执行:
tasks.whenTaskAdded { task ->
if (task.name == 'lint') {
task.enabled = false
}
}
六、知识体系总览
下面这张图总结了Gradle性能调优的核心要点:
七、实战建议
说了这么多,我总结几条最实用的建议:
- 先从
gradle.properties入手:配置JVM参数、开启守护进程、开启并行编译。这三步能解决80%的性能问题。 - 检查你的
build.gradle:看看有没有在配置阶段做耗时操作,有没有滥用allprojects。 - 用
--profile分析构建:执行gradle build --profile,会生成一份HTML报告,告诉你每个阶段花了多少时间。这是定位性能瓶颈的最好方法。 - 定期清理:
./gradlew clean虽然慢,但有时候能解决一些奇怪的问题。我一般每周清理一次。
最后说一句:性能调优不是一蹴而就的事。你每次改一个参数,跑一次构建,看看效果。慢慢积累,你的构建速度就会越来越快。
公众号:蓝海资料掘金营,微信deep3321