较大的项目,或实现大量自定义构建逻辑的项目,可能需要你更深入地了解构建过程以找出瓶颈。你可以通过分析 Gradle 花费在构建生命周期每个阶段和每个构建任务上的时间来做到这一点。例如,如果你的构建配置文件显示 Gradle 在配置你的项目上花费了太多时间,这可能表明你需要将自定义构建逻辑从配置阶段移出。此外,如果mergeDevDebugResources
任务消耗了大量的构建时间,这可能表明你需要将你的图像转换为 WebP或禁用 PNG 压缩.
如果你使用的是 Android Studio 4.0 或更高版本,调查构建性能问题的最佳方法是使用构建分析器.
此外,还有两种在 Android Studio 之外分析构建的选项
独立的
gradle-profiler
工具,一个用于深入分析构建的强大工具。Gradle
--profile
选项,一个从 Gradle 命令行提供的便捷工具。
使用独立的gradle-profiler
工具
为了找到为你提供最佳构建速度的项目设置,你应该使用Gradle 分析器,这是一个用于收集 Gradle 构建的分析和基准信息工具。Gradle 分析器允许你创建构建场景并多次运行它们,防止结果之间出现高度差异并确保结果的可重复性。
基准测试模式应用于收集有关干净和增量构建的信息,而分析模式可用于收集有关运行的更细粒度信息,包括 CPU 快照。
一些用于基准测试的项目设置配置包括
- 插件版本
- Gradle 版本
- JVM 设置(堆大小、permgen 大小、垃圾回收等)
- Gradle 工作线程数 (
org.gradle.workers.max
) - 每个插件的选项以进一步优化性能
入门
- 按照这些说明安装 gradle-profiler
- 运行:
gradle-profiler --benchmark --project-dir <root-project> :app:assembleDebug
这将对一个完全最新的构建进行基准测试,因为--benchmark
会多次运行该任务,而不会在两次运行之间更改项目。然后,它将在profile-out/
目录下生成一个 HTML 报告,向你显示构建时间。
还有其他可能更有用进行基准测试的场景
- 你大部分工作所在的类中方法体内的代码更改。
- 你整个项目中使用的模块的 API 更改。虽然它不像你自己的代码更改那样频繁,但它会产生更大的影响,因此衡量它非常有用。
- 布局编辑以模拟 UI 工作的迭代。
- 字符串编辑以模拟处理翻译工作。
- 清理构建以模拟对构建本身的更改(例如,Android Gradle 插件更新、Gradle 更新或对您自己构建代码的编辑,位于
buildSrc
下)。
为了对这些用例进行基准测试,您可以创建一个将用于驱动 gradle-profiler
执行的场景,并对您的源代码进行适当的更改。您可以查看以下一些常见场景。
分析不同的内存/CPU 设置
为了对不同的内存和 CPU 设置进行基准测试,您可以创建多个场景,这些场景使用 org.gradle.jvmargs
的不同值。例如,您可以创建场景
# <root-project>/scenarios.txt
clean_build_2gb_4workers {
tasks = [":app:assembleDebug"]
gradle-args = ["--max-workers=4"]
jvm-args = ["-Xmx2048m"]
cleanup-tasks = ["clean"]
}
clean_build_parallelGC {
tasks = [":app:assembleDebug"]
jvm-args = ["-XX:+UseParallelGC"]
cleanup-tasks = ["clean"]
}
clean_build_G1GC_4gb {
tasks = [":app:assembleDebug"]
jvm-args = ["-Xmx4096m", "-XX:+UseG1GC"]
cleanup-tasks = ["clean"]
}
运行 gradle-profiler --benchmark --project-dir <root-project> --scenario-file scenarios.txt
将运行三个场景,您将能够比较每个设置下 :app:assembleDebug
所花费的时间。
分析不同的 Gradle 插件版本
为了找出更改 Gradle 插件版本如何影响构建时间,请为基准测试创建一个场景。这需要一些准备工作,以便从场景中注入插件版本。更改您的根 build.gradle
# <root-project>/build.gradle
buildscript {
def agpVersion = providers.systemProperty("agpVersion").forUseAtConfigurationTime().orNull ?: '4.1.0'
ext.kotlin = providers.systemProperty('kotlinVersion').forUseAtConfigurationTime().orNull ?: '1.4.0'
dependencies {
classpath "com.android.tools.build:gradle:$agpVersion"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin"
}
}
现在,您可以从场景文件中指定 Android Gradle 插件和 Kotlin Gradle 插件版本,并让场景向源文件添加一个新方法
# <root-project>/scenarios.txt
non_abi_change_agp4.1.0_kotlin1.4.10 {
tasks = [":app:assembleDebug"]
apply-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
System-properties {
"agpVersion" = "4.1.0"
"kotlinVersion" = "1.4.10"
}
non_abi_change_agp4.2.0_kotlin1.4.20 {
tasks = [":app:assembleDebug"]
apply-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
System-properties {
"agpVersion" = "4.2.0-alpha16"
"kotlinVersion" = "1.4.20"
}
分析增量构建
大多数构建都是增量的,使其成为最需要分析的场景之一。Gradle 分析器对 分析增量构建 有广泛的支持。它能够通过更改方法主体、添加新方法或更改布局或字符串资源来自动将更改应用于源文件。例如,您可以创建如下增量场景
# <root-project>/scenarios.txt
non_abi_change {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to = ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
}
abi_change {
tasks = [":app:assembleDebug"]
apply-abi-change-to = ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
}
layout_change {
tasks = [":app:assembleDebug"]
apply-android-layout-change-to = "app/src/main/res/your_layout_file.xml"
}
string_resource_change {
tasks = [":app:assembleDebug"]
apply-android-resource-value-change-to = "app/src/main/res/values/strings.xml"
}
运行 gradle-profiler --benchmark --project-dir <root-project> --scenario-file scenarios.txt
将生成包含基准测试数据的 HTML 报告。
您可以将增量场景与其他设置组合起来,例如堆大小、工作程序数量或 Gradle 版本
# <root-project>/scenarios.txt
non_abi_change_4g {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
jvm-args = ["-Xmx4096m"]
}
non_abi_change_4g_8workers {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
jvm-args = ["-Xmx4096m"]
gradle-args = ["--max-workers=8"]
}
non_abi_change_3g_gradle67 {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
jvm-args = ["-Xmx3072m"]
version = ["6.7"]
}
分析清理构建
为了对清理构建进行基准测试,您可以创建一个将用于驱动 gradle-profiler 执行的场景
# <root-project>/scenarios.txt
clean_build {
tasks = [":app:assembleDebug"]
cleanup-tasks = ["clean"]
}
要运行此场景,请使用以下命令
gradle-profiler --benchmark --project-dir <root-project> --scenario-file scenarios.txt
使用 Gradle --profile
选项
要从 Gradle 命令行生成和查看构建配置文件,请执行以下步骤
- 在项目的根目录处打开一个命令行终端。
- 通过输入以下命令执行清理构建。在分析构建时,您应该在分析的每次构建之间执行清理构建,因为 Gradle 会跳过任务,当任务的输入(例如源代码)没有改变时。因此,没有输入更改的第二次构建总是运行得更快,因为任务没有重新运行。因此,在构建之间运行
clean
任务可确保您分析完整的构建过程。// On Mac or Linux, run the Gradle wrapper using "./gradlew". gradlew clean
- 使用以下标志执行您其中一个产品风味的调试构建,例如“dev”风味
gradlew --profile --offline --rerun-tasks assembleFlavorDebug
-
--profile
:启用分析。 -
--offline
:禁用 Gradle 获取在线依赖项。这确保 Gradle 尝试更新您的依赖项造成的任何延迟不会干扰您的分析数据。您应该已经构建过项目一次,以确保 Gradle 已经下载并缓存了您的依赖项。 -
--rerun-tasks
:强制 Gradle 重新运行所有任务并忽略任何任务优化。
-
-
构建完成后,使用项目窗口导航到
project-root/build/reports/profile/
目录(如图 1 所示)。 -
右键单击
profile-timestamp.html
文件,然后选择在浏览器中打开 > 默认。报告应类似于图 2 中显示的报告。您可以检查报告中的每个选项卡以了解您的构建,例如任务执行选项卡,其中显示 Gradle 执行每个构建任务所花费的时间。 -
可选: 在对项目或构建配置进行任何更改之前,重复步骤 3 中的命令,但省略
--rerun-tasks
标志。由于 Gradle 尝试通过不重新执行输入未更改的任务来节省时间(这些任务在报告的任务执行选项卡中标记为UP-TO-DATE
,如图 3 所示),因此您可以识别哪些任务在不应该运行时执行工作。例如,如果:app:processDevUniversalDebugManifest
未标记为UP-TO-DATE
,则可能表明您的构建配置正在每次构建时动态更新清单。但是,某些任务需要在每次构建时运行,例如:app:checkDevDebugManifest
。
现在您拥有了构建配置文件报告,您可以通过检查报告中每个选项卡的信息来开始寻找优化机会。某些构建设置需要进行实验,因为其益处可能因项目和工作站而异。例如,具有大型代码库的项目可能会受益于 代码缩减,以删除未使用的代码并缩减应用程序大小。但是,较小的项目可能会从完全禁用代码缩减中获得更多益处。此外,增加 Gradle 堆大小(使用 org.gradle.jvmargs
)可能会对低内存机器上的性能产生负面影响。
在对构建配置进行更改后,通过重复上述步骤并生成新的构建配置文件来观察更改的结果。例如,图 4 显示了在应用本页所述的一些基本优化后,同一示例应用程序的报告。