如何优化Gradle构建性能,以减少构建时间和RAM使用?

45

我目前正在将我的多模块Web应用从Ant迁移到Gradle,目前看来当前版本的Gradle(M9)可能已经到达其极限。但也许(希望)只是我不太理解Gradle的概念或不知道“魔法性能提升开关”的问题。我很乐意听取有关如何优化构建性能的任何提示。

问题:在显示第一个compileJava之前要等待几分钟,即使在源中没有更改,进程也至少运行了7分钟,直到在:testClasses(在不同的子项目中)崩溃并显示以下消息:

* What went wrong:
Could not resolve all dependencies for configuration ':mysubproject_X:testRuntime'.
> Java heap space

该项目由大约30个(部分相互依赖的)子项目组成,它们的build.gradle文件大多数相同,用于从每个子项目构建一个jar文件,例如:

sourceSets {

    main {
        java {
            srcDirs 'src'
        }
    }
}

dependencies {

    compile project(':mysubproject_A')
    compile project(':mysubproject_B')
    compile project(':mysubproject_E')

    compile group: 'commons-lang', name: 'commons-lang', version: '2.2'

}

// copy all non-java files from src
copy {
    from sourceSets.main.java.srcDirs
    into "$buildDir/classes/main"
    exclude '**/*.java'
}

jar {
}

我尝试通过将最大内存大小增加到1024M来解决堆空间问题,但没有帮助。我的主要build.gradle文件如下:

            sourceCompatibility = 1.6
            version = 0.5

            useFindBugs = false

            apply plugin: 'java'

            configurations {
            }

            repositories {
                mavenCentral()
                mavenRepo url:"http://repository.jboss.org/maven2", artifactUrls: ["https://repository.jboss.org/nexus/content/repositories/public","http://opensource.55minutes.com/maven-releases"]
            }


            dependencies {
            }

            buildscript {
                repositories {
                    mavenRepo url: 'http://gradle.artifactoryonline.com/gradle/plugins'
                    flatDir(dirs: "$projectDir/lib")
                }

                dependencies {
                    classpath "org.gradle.plugins:gradle-idea-plugin:0.3.1"
                }
            }

            subprojects {
                apply plugin: 'java'
                apply plugin: 'idea'

                repositories {
                    mavenCentral()
                    mavenRepo url:"http://repository.jboss.org/maven2", artifactUrls: ["https://repository.jboss.org/nexus/content/repositories/public","http://opensource.55minutes.com/maven-releases"]
                }

                dependencies {
                    testCompile 'junit:junit:4.8.2'
                }

                compileJava {
                    options.encoding = 'UTF-8'
                    options.fork (memoryMaximumSize: '1024m') 
                }

                javadoc {
                    options.encoding = 'UTF-8'
                }

                test {
                    testReportDir = file(rootProject.testReportDir)
                    forkEvery = 1
                    jvmArgs = ['-ea', '-Xmx1024m']
                }
            }


            dependsOnChildren()

            task wrapper(type: Wrapper) {
                gradleVersion = '1.0-milestone-9'
            }

1
你是否正在替换令牌?我发现这是导致多项目 Gradle 构建速度慢数倍的唯一原因,因为我们正在对 .gradle 缓存进行令牌替换。 - Eric Wendelin
谢谢您的建议。然而,并没有涉及到替换。Peter Niederwieser在下面的回答解决了问题 :) - peterp
9个回答

66

您需要为Gradle JVM分配更多内存,而不是编译任务/JVM。一种方法是通过GRADLE_OPTS环境变量来实现(GRADLE_OPTS=-Xmx512m)。


6
谢谢。如建议的那样将GRADLE_OPTS设置为-Xmx512m不仅消除了堆空间错误,还极大地加快了进程速度。构建仍然需要相当长的时间,并且在某些时候我不太确定Gradle在后台做什么,但我可以从这里继续使用分析工具 :) - peterp
当将其设置为512时,我再次收到相同的错误;但是当我将其设置为例如2048时,我会收到“无法为2097152保留足够的空间”的错误。 - Dr.jacky

29
如果使用Gradle Wrapper,你可以像这样在gradlew中设置DEFAULT_JVM_OPTS
DEFAULT_JVM_OPTS="-Xmx512m"

如果你使用的是Windows,在gradlew.bat中以类似的方式设置:

set DEFAULT_JVM_OPTS=-Xmx512m

Gradle Wrapper任务也可以进行修改,以自动包含此内容。这就是Gradle开发人员解决此问题的方法:

wrapper {
    gradleVersion = '1.8'

    def jvmOpts = "-Xmx512m"
    inputs.property("jvmOpts", jvmOpts)
    doLast {
        def optsEnvVar = "DEFAULT_JVM_OPTS"
        scriptFile.write scriptFile.text.replace("$optsEnvVar=\"\"", "$optsEnvVar=\"$jvmOpts\"")
        batchScript.write batchScript.text.replace("set $optsEnvVar=", "set $optsEnvVar=$jvmOpts")
    }
}

修改包装任务在Gradle 2.9上也能正常工作 - nerdherd
我建议在提供代码片段时,您应该同时说明相关文件及其文件路径。 - The Oracle
据我所记,这可以放置在任何Gradle构建文件中。 - David Pärsson

9

我正在使用以下版本的gradle.properties,以提高在Android项目中使用Gradle的性能:

# The Gradle daemon aims to improve the startup and execution time of Gradle.
# When set to true the Gradle daemon is to run the build.
org.gradle.daemon=true

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
org.gradle.parallel=true

# Enables new incubating mode that makes Gradle selective when configuring projects.
# Only relevant projects are configured which results in faster builds for large multi-projects.
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:configuration_on_demand
org.gradle.configureondemand=true

1
这个很好用,尽管我不得不在我的项目中禁用并行处理,我认为这是因为一个自定义的Gradle插件正在改变现有的JAR文件而不是产生新的输出并保留原始文件。如果并行处理对其他人没有按预期工作,那么这是值得思考的。 - Coder Guy

7

我刚刚找到了一个非常好的处理这个问题的方法。不需要自定义 gradle wrapper 或者 GRADLE_OPTIONS。

compileJava {
    options.fork = true  // Fork your compilation into a child process
    options.forkOptions.setMemoryMaximumSize("4g") // Set maximum memory to 4g
}

使用--info选项运行Gradle,可以查看它将在哪里使用您的最大内存大小参数。

gradle build --info

1
在您的build.grade文件中,语法已经有了一些变化。这是JavaCompile文档 - Dusan Jovanovic

4

似乎在某个点上超载了Java堆大小,过了一会儿就将其删除了。现在考虑使用SSD硬盘作为下一阶段的性能提升。 - shimi_tap
Gradle守护进程默认已启用。 - K''

4
请将以下内容放入 ~/.gradle/gradle.properties 文件中:
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Settings specified in this file will override any Gradle settings
# configured through the IDE.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# The Gradle daemon aims to improve the startup and execution time of Gradle.
# When set to true the Gradle daemon is to run the build.
# TODO: disable daemon on CI, since builds should be clean and reliable on servers
org.gradle.daemon=true
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
org.gradle.jvmargs=-Xmx6g -Xms4g -XX:MaxPermSize=8g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
org.gradle.parallel=true
# Enables new incubating mode that makes Gradle selective when configuring projects.
# Only relevant projects are configured which results in faster builds for large multi-projects.
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:configuration_on_demand
org.gradle.configureondemand=true

1
打开Gradle守护进程通常可以有效加速Gradle。每次调用Gradle时,它都需要加载和解析构建文件,然后才能开始执行。守护进程将加载/解析并缓存已解析的数据。下一次调用,如果构建文件没有更改,速度会快得多。但是,如果您尝试查看类路径、变量值等信息,例如“gradle --debug <task>”,则会失败。您必须在配置中关闭守护进程,kill -9该进程,然后执行--debug。完成调试后,再在配置中重新启用守护进程。 - Meower68

3

我个人阅读了这里的所有文章,但是按照以下步骤解决了问题。

如果您正在使用32位JVM,则可能是问题所在,请安装64位JVM。

  1. Go to the control panel (search java in windows 10)
  2. find the java application
  3. Double click on java and then view.
  4. In run time parameters add:

    -Xmx 2048m
    

1
对于任何寻找“运行时参数”的人,在W7中,这是在第3步完成后的“Java”选项卡下,然后单击“查看”。从那里,“运行时参数”将被视为网格中的一个单元格。 - www-0av-Com
谢谢!我安装了32位和64位的Java,但gradle使用了32位而不是64位。 - blk0ut

1

以上答案都对我没用,后来我找到了这个-

我的系统配置-

Windows x64 - JDK 32 bit - Cordova 5.4.1 - Ionic 1.7.12

运行Gradle时可以通过环境变量设置JVM选项。您可以使用GRADLE_OPTS或JAVA_OPTS,也可以同时使用两者。按照惯例,JAVA_OPTS是许多Java应用程序共享的环境变量。典型用例是在JAVA_OPTS中设置HTTP代理,在GRADLE_OPTS中设置内存选项。这些变量也可以在gradle或gradlew脚本的开头设置。

我添加了下面提到的两个环境变量,并解决了这个问题-

Variable Name: GRADLE_OPTS
Variable Value: -Xmx512m

Variable Name: JAVA_OPTS
Variable Value: -Xmx512m

希望这对像我这样的人有所帮助。

0

我的gradlew中GRADLE_OPTS的值设置如下:

DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"

这会导致在Jenkins中编译Java时出现以下错误:

出现了什么问题: 任务“:compileJava”执行失败。 GC超时限制已超过
后来,我更改了DEFAULT_JVM_OPTS,如下所示,以使Jekin构建成功 -
DEFAULT_JVM_OPTS =“-Xmx512m”“-Xms64m”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接