直接查看build --scan报告的“plugins”页签可快速定位拖慢构建的插件,它会显示各插件加载耗时、激活状态及是否触发脚本解析;声明式plugins { id "xxx" }引入的插件会被单独统计,而apply plugin:命令式写法则归入“legacy plugin application”,难以追踪且易导致初始化污染、重复加载及configuration-cache不兼容。

Gradle构建慢,怎么确认是哪个插件在拖后腿
直接看build --scan报告里的“Plugins”页签,比翻日志快十倍。Build Scan会把每个插件的加载耗时、激活状态、是否触发了脚本解析(script evaluation)都标出来。如果某个插件旁边显示“activation: 12.4s”,而其他都在毫秒级,基本就是它了。
注意:不是所有插件都会出现在这个列表里——只有通过plugins { id "xxx" }声明式方式引入的才会被统计;用apply plugin: "xxx"这种命令式写法的,会被归到“legacy plugin application”里,得手动查。
为什么apply plugin:写法会让排查变难
命令式插件应用(apply plugin:)绕过了Gradle的插件生命周期管理,IDE和Build Scan无法准确追踪它的初始化时机和依赖链。更麻烦的是,它可能在build.gradle任意位置执行,导致:
- 插件提前加载了不该加载的类(比如在
configure块里就apply),污染了配置阶段 - 多个模块重复
apply同一个插件,但Gradle不报错也不合并,只是默默多跑几遍初始化逻辑 - 和
configuration-cache不兼容,一启用就报Plugin 'xxx' is not compatible with configuration cache
检查项目里所有build.gradle,搜apply plugin:和apply from:,优先替换成plugins { id "xxx" version "y.z" }写法。
插件加载慢的典型表现和对应动作
遇到以下现象,大概率是插件问题,别急着调-Xmx:
-
gradle --stop && gradlew build --no-daemon --info比带daemon还快 → 插件初始化没复用,daemon被插件污染了 - 构建日志里反复出现
Evaluating project ':module-x' using build file '.../build.gradle'→ 某个插件在afterEvaluate里又触发了重解析 -
./gradlew build --scan报告中,“Configuration”阶段耗时占比>60%,且“Script compilation”时间异常高 → 插件脚本本身太重,或依赖了大量未缓存的DSL扩展
临时验证方法:在settings.gradle顶部加enableFeaturePreview('typesafe-project-accessors'),再删掉所有apply plugin:,只保留plugins { },观察构建时间变化。如果明显下降,说明旧写法是主因。
哪些插件最容易成为性能黑洞
不是所有插件都平等。这几类要特别小心:
- 带
io.gitlab.arturbosch.detekt、org.jlleitschuh.gradle.ktlint这类静态检查插件:默认会在compileJava前插入任务,且每次都要加载完整规则集。建议改用detekt { buildUponDefaultConfig = true }并显式禁用不用的规则 - 自定义插件用了
project.afterEvaluate+tasks.withType(JavaCompile)遍历:在多模块项目里,这会导致N×M次反射调用,极易卡死 - Android项目里还在用
com.github.triplet.play老版本(<3.8.0):它会为每个variant动态注册publish任务,模块越多越慢
真正难缠的不是插件本身,而是它把configuration阶段拉长后,导致Gradle无法有效启用configuration-cache和parallel。一旦这两个关了,整个构建就退化成单线程顺序执行——这时候再加内存也没用。











