Gradle Daemon
Daemon process 的定义:
A daemon is a computer program that runs as a background process, rather than being under the direct control of an interactive user. ————Wikipedia
我帮大家翻译过来就是:守护进程是作为后台进程运行的计算机程序,不受交互用户的直接控制。 如果大家对 Java 的线程熟悉的话,肯定知道 Java 的线程也有一个 daomon 的参数,可以将这个线程设置为守护线程,这里的 守护线程的概念和上面的维基百科里的概念一样,运行在后台,不直接处理用户交互逻辑。关于Daemon 的概念就先介绍到这里。
大家都知道 Gradle 是运行在 Java 虚拟机上的并且它需要的几个support libraries 都需要一定的初始化时间,所以 Gradle 的初始化是需要一定的时间的。解决这个问题的方法就是 Gradle Daemon,守护进程:一个长时间运行在后台的进程,避免频繁的初始化。并且 Gradle 会将 Project data 缓存在内存中,加快构建速度。使用Gradle Daemon 是没有任何副作用的,并且我们可以非常简单的使用它,不需要任何成本,Gradle Daomen 对我们用户是完全透明的。
为什么 Gradle Daemon 对提升构建的表现是很重要的
Daemon 是一个长生命周期的进程,这不仅仅可以避免每次启动构建时的初始化所带来的资源消耗,而且可以缓存 project、task、output、files等数据在内存中。
理由很简单:通过重用以前构建的计算结果来提高构建速度。并且这样做的好处是非常显著的:我们得出的结论是在后续的构建中构建的时间通常可以减少15-75%。我们建议使用——profile
来分析你的构建,了解Gradle守护进程对构建的影响有多大。
在 Gradle3.0 之后 Gradle Daemon 是默认开启的
查看守护进程的状态
使用--status
来查看守护进程的状态
./gradlew --status
gradle --status
这是一个例子:
PID VERSION STATUS
28411 3.0 IDLE
34247 3.0 BUSY
需要注意的是这里只会显示与被调用 Gradle 的同版本的守护进程,而不会显示其他版本的进程。在未来 Gradle 可能会接触这一个限制,并将现实所有版本的运行中的守护进程。
关闭 Gradle Daemon 功能
默认情况下,Gradle守护进程是启用的,我们建议始终启用它。你可以通过命令行选项——no-daemon
禁用Gradle守护进程,或者添加org.gradle。daemon=false
配置在 gradle.properties
文件中。
为了满足构建所需的JVM选项,Gradle通常会为构建生成一个单独的进程,即使守护进程的选项被禁用。
如果守护进程的选项被禁用,那么为了满足构建所需的JVM选项,Gradle通常会在每次构建的时候创建新的单独的进程。
Note: 不管是哪一个Gradle版本,在开启守护进程选项后,Gradle的构建速度都会有很大的提升
在 Gradle 3.0 后,守护进程默认是开启的,无论是开发机还是服务器,我们都推荐使用守护进程。不过如果我们觉得在服务器上进行CI流程时,开启守护进程会对构建会产生不稳定因素,那么我们可以关闭守护进程的选项。因为每次构建都会创建新的进程,
停止正在运行的守护进程
如上所述,守护进程是一个后台进程。不过,您不必担心在您的机器上构建Gradle进程的内存使用情况。每个守护进程都监控自己的内存使用情况,并将其与系统总内存进行比较,当可用的系统内存较低时,守护进程将在空闲时停止自身。如果你想显式地停止运行守护进程,只要使用gradle——stop命令即可。
gradle --stop
这将终止所有使用同一个版本的Gradle启动的守护进程。如果已经安装了Java开发工具包(JDK),那么您可以通过运行jps命令轻松地验证守护进程是否已经停止。
FAQ
我怎么禁用Gradle 守护进程?
这里有两种推荐的方法可以禁用守护进程:
- 通过环境变量: 添加标志
-Dorg.gradle.daemon=false
到GRADLE_OPTS
环境变量 - 通过
build.properties
文件: 添加org.gradledaemon=false
到«GRADLE_USER_HOME»/gradle.properties
文件中
这两种方法都有相同的效果。用哪一种取决于个人喜好。不过我们大多数开发者选择第二个选项,通过向 build.properties 文件添加选项的方法
windows:
(if not exist "%USERPROFILE%/.gradle" mkdir "%USERPROFILE%/.gradle") && (echo. >> "%USERPROFILE%/.gradle/gradle.properties" && echo org.gradle.daemon=false >> "%USERPROFILE%/.gradle/gradle.properties")
UNIX-like:
mkdir -p ~/.gradle && echo "org.gradle.daemon=false" >> ~/.gradle/gradle.properties
一旦在构建环境中上述种方式禁用了守护进程,Gradle守护进程将不会被启动,除非使用——Daemon选项
显式地请求。
当使用Gradle命令行时,——daemon
和——no-daemon
命令行选项可以启用或禁用单次构建调用的守护进程。在考虑构建环境时,这些命令行选项具有最高的优先级。通常,为环境启用守护进程更方便,这样所有构建都使用守护进程,而不需要记住提供——Daemon
选项。
为什么我的电脑有多个守护进程?
Gradle创建一个新的守护进程,而不是使用一个已经在运行的守护进程的几个基本规则是,如果没有空闲或兼容的守护进程,Gradle将启动一个新的守护进程。Gradle会杀死任何闲置3小时以上的守护进程,所以不必担心手动清理它们。
- idle:是指当前没有执行构建或执行其他有用工作的守护进程。
- compatible:compatible daemon 进程是能够满足所请求的构建环境的要求的守护进程。用于执行构建的Java运行时是构建环境的一个示例方面。另一个示例是构建运行时所需的JVM系统属性集。
守护进程可能无法满足所请求的构建环境的某些选项或者配置。如果守护进程与Java 8运行时一起运行,但是所请求的环境调用Java 10,那么守护进程不兼容,必须启动另一个守护进程。而且,一旦JVM启动,Java运行时的某些属性就不能更改。例如,不能更改运行中的JVM的内存分配(例如-Xmx1024m)、默认文本编码、默认区域设置等。
以下JVM系统属性实际上是不可变的。如果所请求的构建环境需要这些属性中的任何一个,且这些属性的值与守护进程的JVM对该属性的值不同,则守护进程是不兼容的。
-
file.encoding
-
user.language
-
user.country
-
user.variant
-
java.io.tmpdir
-
javax.net.ssl.keyStore
-
javax.net.ssl.keyStorePassword
-
javax.net.ssl.keyStoreType
-
javax.net.ssl.trustStore
-
javax.net.ssl.trustStorePassword
-
javax.net.ssl.trustStoreType
-
com.sun.management.jmxremote
以下由启动参数控制的JVM属性实际上也是不可变的。为了使守护进程兼容,被请求的构建环境和守护进程的环境的相应属性必须完全匹配。
-
The maximum heap size (i.e. the -Xmx JVM argument)
-
The minimum heap size (i.e. the -Xms JVM argument)
-
The boot classpath (i.e. the -Xbootclasspath argument)
-
The “assertion” status (i.e. the -ea argument)
在使用不同Gradle版本时同时处理多个Gradle项目也是拥有多个运行守护进程的常见原因。
守护进程使用多少内存,我可以给它更多吗?
如果所请求的构建环境没有指定最大堆大小,守护进程将使用最多512MB的堆。它将使用JVM的默认最小堆大小。512MB对于大多数构建来说已经足够了。带有数百个子项目、大量配置和源代码的大型构建可能需要更多内存,或者性能更好。
要增加守护进程可以使用的内存量,可以为构建环境指定适当的标志位或者选项
我如何停止一个守护进程?
守护进程将在3小时或更短的时间内自动终止。如果你想在此之前停止一个守护进程,你可以通过你的操作系统或者运行gradle --stop
命令来终止这个进程。——stop
开关会导致Gradle请求所有正在运行的守护进程(与运行该命令所用的Gradle版本相同)自行终止。
守护进程会出什么问题?
Gradle 团队已经将大量的工程工作投入到守护进程的开发中,使守护进程在日常开发中健壮、透明。但是,守护进程偶尔也会损坏或出现问题。Gradle构建可以执行多种源代码的任意代码。虽然Gradle本身是为守护进程设计的,并且经过了大量的测试,但是用户构建脚本和第三方插件可能会通过诸如内存泄漏或全局状态破坏等缺陷破坏守护进程。
运行没有正确释放资源的构建也可能破坏守护进程(以及一般的构建环境)的稳定。在使用微软Windows系统时,这是一个特别尖锐的问题,因为它不太能容忍程序在读取或写入文件后无法关闭文件。
Gradle会主动监控堆的使用情况,并尝试检测何时泄漏开始耗尽守护进程中的可用堆空间。当它检测到一个问题时,Gradle守护进程将完成当前正在运行的构建,并在下一次构建时主动重启该守护进程。这种监视在默认情况下是启用的,但是可以通过设置org.gradle.daemon.performance.enable-monitoring
为false来禁用。
如果怀疑守护进程变得不稳定,可以简单地杀死它。回想一下,可以为构建指定——no-daemon开关,以防止使用守护进程。这对于诊断这个守护进程是否是问题的罪魁祸首是很有用的。
为什么守护进程就加快构建速度?
Gradle守护进程是一个长期存在的进程。在构建期间,它会空闲地等待下一次构建。这有一个明显的好处,即在多次构建时只需要将Gradle加载到内存中一次,而不是每次构建时加载一次。这本身就是一个显著的性能优化,但它还不止于此。
现代JVM性能的一个重要部分是运行时代码优化。例如,HotSpot (Oracle提供的JVM实现,用作OpenJDK的基础)会在代码运行时对其进行优化。优化是渐进的,而不是瞬间的。也就是说,代码会在执行过程中逐步优化,这意味着后续的构建会因为这个优化过程而变得更快。HotSpot的实验表明,需要5到10个构建才能实现稳定的优化。对于一个守护进程,第一次构建和第10次构建在构建时间上的差异是非常显著的。
这个守护进程还允许不同构建之间进行更有效的内存缓存。例如,构建所需的类(例如插件、构建脚本)可以在构建之间保存在内存中。类似地,Gradle可以维护构建数据的内存缓存,比如任务输入和输出的散列,用于增量构建。
为了检测文件系统的变化,并计算需要重新构建的内容,Gradle会在每次构建时收集大量有关文件系统状态的信息。在启用监视文件系统时,守护进程可以重用从上次构建中收集到的信息。这可以为增量构建节省大量时间,因为在两个构建之间,文件系统的更改数量通常很低。