The Gradle Daemon
A daemon is a computer program that runs as a background process, rather than being under the direct control of an interactive user.
Gradle runs on the Java Virtual Machine (JVM) and uses several supporting libraries that require a non-trivial initialization time. As a result, it can sometimes seem a little slow to start. The solution to this problem is the Gradle Daemon: a long-lived background process that executes your builds much more quickly than would otherwise be the case. We accomplish this by avoiding the expensive bootstrapping process as well as leveraging caching, by keeping data about your project in memory. Running Gradle builds with the Daemon is no different than without. Simply configure whether you want to use it or not — everything else is handled transparently by Gradle.
The Daemon is a long-lived process, so not only are we able to avoid the cost of JVM startup for every build, but we are able to cache information about project structure, files, tasks, and more in memory.
The reasoning is simple: improve build speed by reusing computations from previous builds. However, the benefits are dramatic: we typically measure build times reduced by 15-75% on subsequent builds. We recommend profiling your build by using
--profile to get a sense of how much impact the Gradle Daemon can have for you.
The Gradle Daemon is enabled by default starting with Gradle 3.0, so you don’t have to do anything to benefit from it.
To get a list of running Gradle Daemons and their statuses use the
PID VERSION STATUS 28411 3.0 IDLE 34247 3.0 BUSY
Currently, a given Gradle version can only connect to daemons of the same version. This means the status output will only show Daemons for the version of Gradle being invoked and not for any other versions. Future versions of Gradle will lift this constraint and will show the running Daemons for all versions of Gradle.
The Gradle Daemon is enabled by default, and we recommend always enabling it. You can disable the long-lived Gradle daemon via the
--no-daemon command-line option, or by adding
org.gradle.daemon=false to your
gradle.properties file. You can find details of other ways to disable (and enable) the Daemon in Daemon FAQ further down.
In order to honour the required JVM options for your build, Gradle will normally spawn a separate process for build invocation, even when the Daemon is disabled. You can prevent this "single-use Daemon" by ensuring that the JVM settings for the client VM match those required for the build VM. See Configuring JVM Memory for more details.
Note that having the Daemon enabled, all your builds will take advantage of the speed boost, regardless of the version of Gradle a particular build uses.
Since Gradle 3.0, we enable Daemon by default and recommend using it for both developers' machines and Continuous Integration servers. However, if you suspect that Daemon makes your CI builds unstable, you can disable it to use a fresh runtime for each build since the runtime is completely isolated from any previous builds.
As mentioned, the Daemon is a background process. You needn’t worry about a build up of Gradle processes on your machine, though. Every Daemon monitors its memory usage compared to total system memory and will stop itself if idle when available system memory is low. If you want to explicitly stop running Daemon processes for any reason, just use the command
This will terminate all Daemon processes that were started with the same version of Gradle used to execute the command. If you have the Java Development Kit (JDK) installed, you can easily verify that a Daemon has stopped by running the
jps command. You’ll see any running Daemons listed with the name
There are two recommended ways to disable the Daemon persistently for an environment:
Via environment variables: add the flag
Via properties file: add
Both approaches have the same effect. Which one to use is up to personal preference. Most Gradle users choose the second option and add the entry to the user
On Windows, this command will disable the Daemon for the current user:
(if not exist "%USERPROFILE%/.gradle" mkdir "%USERPROFILE%/.gradle") && (echo. >> "%USERPROFILE%/.gradle/gradle.properties" && echo org.gradle.daemon=false >> "%USERPROFILE%/.gradle/gradle.properties")
On UNIX-like operating systems, the following Bash shell command will disable the Daemon for the current user:
mkdir -p ~/.gradle && echo "org.gradle.daemon=false" >> ~/.gradle/gradle.properties
Once the Daemon is disabled for a build environment in this way, a Gradle Daemon will not be started unless explicitly requested using the
--no-daemon command line options enable and disable usage of the Daemon for individual build invocations when using the Gradle command line interface. These command line options have the highest precedence when considering the build environment. Typically, it is more convenient to enable the Daemon for an environment (e.g. a user account) so that all builds use the Daemon without requiring to remember to supply the
There are several reasons why Gradle will create a new Daemon, instead of using one that is already running. The basic rule is that Gradle will start a new Daemon if there are no existing idle or compatible Daemons available. Gradle will kill any Daemon that has been idle for 3 hours or more, so you don’t have to worry about cleaning them up manually.
An idle Daemon is one that is not currently executing a build or doing other useful work.
A compatible Daemon is one that can (or can be made to) meet the requirements of the requested build environment. The Java runtime used to execute the build is an example aspect of the build environment. Another example is the set of JVM system properties required by the build runtime.
Some aspects of the requested build environment may not be met by an Daemon. If the Daemon is running with a Java 8 runtime, but the requested environment calls for Java 10, then the Daemon is not compatible and another must be started. Moreover, certain properties of a Java runtime cannot be changed once the JVM has started. For example, it is not possible to change the memory allocation (e.g.
-Xmx1024m), default text encoding, default locale, etc of a running JVM.
The “requested build environment” is typically constructed implicitly from aspects of the build client’s (e.g. Gradle command line client, IDE etc.) environment and explicitly via command line switches and settings. See Build Environment for details on how to specify and control the build environment.
The following JVM system properties are effectively immutable. If the requested build environment requires any of these properties, with a different value than a Daemon’s JVM has for this property, the Daemon is not compatible.
The following JVM attributes, controlled by startup arguments, are also effectively immutable. The corresponding attributes of the requested build environment and the Daemon’s environment must match exactly in order for a Daemon to be compatible.
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)
The required Gradle version is another aspect of the requested build environment. Daemon processes are coupled to a specific Gradle runtime. Working on multiple Gradle projects during a session that use different Gradle versions is a common reason for having more than one running Daemon process.
If the requested build environment does not specify a maximum heap size, the Daemon will use up to 512MB of heap. It will use the JVM’s default minimum heap size. 512MB is more than enough for most builds. Larger builds with hundreds of subprojects, lots of configuration, and source code may require, or perform better, with more memory.
To increase the amount of memory the Daemon can use, specify the appropriate flags as part of the requested build environment. Please see Build Environment for details.
Daemon processes will automatically terminate themselves after 3 hours of inactivity or less. If you wish to stop a Daemon process before this, you can either kill the process via your operating system or run the
gradle --stop command. The
--stop switch causes Gradle to request that all running Daemon processes, of the same Gradle version used to run the command, terminate themselves.
Considerable engineering effort has gone into making the Daemon robust, transparent and unobtrusive during day to day development. However, Daemon processes can occasionally be corrupted or exhausted. A Gradle build executes arbitrary code from multiple sources. While Gradle itself is designed for and heavily tested with the Daemon, user build scripts and third party plugins can destabilize the Daemon process through defects such as memory leaks or global state corruption.
It is also possible to destabilize the Daemon (and build environment in general) by running builds that do not release resources correctly. This is a particularly poignant problem when using Microsoft Windows as it is less forgiving of programs that fail to close files after reading or writing.
Gradle actively monitors heap usage and attempts to detect when a leak is starting to exhaust the available heap space in the daemon. When it detects a problem, the Gradle daemon will finish the currently running build and proactively restart the daemon on the next build. This monitoring is enabled by default, but can be disabled by setting the
org.gradle.daemon.performance.enable-monitoring system property to false.
If it is suspected that the Daemon process has become unstable, it can simply be killed. Recall that the
--no-daemon switch can be specified for a build to prevent use of the Daemon. This can be useful to diagnose whether or not the Daemon is actually the culprit of a problem.
The Gradle Tooling API that is used by IDEs and other tools to integrate with Gradle always uses the Gradle Daemon to execute builds. If you are executing Gradle builds from within your IDE you are using the Gradle Daemon and do not need to enable it for your environment.
The Gradle Daemon is a long lived build process. In between builds it waits idly for the next build. This has the obvious benefit of only requiring Gradle to be loaded into memory once for multiple builds, as opposed to once for each build. This in itself is a significant performance optimization, but that’s not where it stops.
A significant part of the story for modern JVM performance is runtime code optimization. For example, HotSpot (the JVM implementation provided by Oracle and used as the basis of OpenJDK) applies optimization to code while it is running. The optimization is progressive and not instantaneous. That is, the code is progressively optimized during execution which means that subsequent builds can be faster purely due to this optimization process. Experiments with HotSpot have shown that it takes somewhere between 5 and 10 builds for optimization to stabilize. The difference in perceived build time between the first build and the 10th for a Daemon can be quite dramatic.
The Daemon also allows more effective in memory caching across builds. For example, the classes needed by the build (e.g. plugins, build scripts) can be held in memory between builds. Similarly, Gradle can maintain in-memory caches of build data such as the hashes of task inputs and outputs, used for incremental building.
To detect changes on the file system, and to calculate what needs to be rebuilt, Gradle collects a lot of information about the state of the file system during every build. On supported operating systems the Daemon re-uses the already collected information from the last build (see watching the file system). This can save a significant amount of time for incremental builds, where the number of changes to the file system between two builds is typically low.
To detect changes on the file system, and to calculate what needs to be rebuilt, Gradle collects information about the file system in-memory during every build (aka Virtual File System). By watching the file system, Gradle can keep the Virtual File System in sync with the file system even between builds. Doing so allows the Daemon to save the time to rebuild the Virtual File System from disk for the next build. For incremental builds, there are typically only a few changes between builds. Therefore, incremental builds can re-use most of the Virtual File System from the last build and benefit the most from watching the file system.
Gradle uses native operating system features for watching the file system. It supports the feature on these operating systems:
Windows 10 (earlier versions likely work, but are not tested),
Linux (Ubuntu 16.04 or later, CentOS 8 or later, Red Hat Enterprise Linux 8 or later, Amazon Linux 2 are tested),
macOS 10.14 (Mojave) or later (Intel and ARM Macs included).
The feature supports the following file system types:
File system watching supports working through VirtualBox’s shared folders, too.
Network file systems like Samba and NFS are not supported.
If you have symlinks in your build, you won’t get the performance benefits for those locations.
File system watching is enabled by default for operating systems supported by Gradle.
When the feature is enabled by default, Gradle acts conservatively when it encounters content on unsupported file systems. This can happen for example if a project directory, or one of its subdirectories is mounted from a network drive. In default mode information about unsupported file systems will not be retained in the Virtual File System between builds.
To force Gradle to keep information about unsupported file systems between builds, the feature must be enabled explicitly by one of these methods:
- Run with
--watch-fson the command line
This forces watching the file system for this build only.
This forces watching the file system for all builds, unless explicitly disabled with
File system watching can also be disabled completely regardless of file systems by supplying
--no-watch-fs on the command-line, or by specifying
You can instruct Gradle to some more information about the state of the virtual file system, and the events received from the file system using the
This produces the following output at the start and end of the build:
$ gradle assemble --watch-fs -Dorg.gradle.vfs.verbose=true Received 3 file system events since last build while watching 1 hierarchies Virtual file system retained information about 2 files, 2 directories and 0 missing files since last build > Task :compileJava NO-SOURCE > Task :processResources NO-SOURCE > Task :classes UP-TO-DATE > Task :jar UP-TO-DATE > Task :assemble UP-TO-DATE BUILD SUCCESSFUL in 58ms 1 actionable task: 1 up-to-date Received 5 file system events during the current build while watching 1 hierarchies Virtual file system retains information about 3 files, 2 directories and 2 missing files until next build
+ Note that on Windows and macOS Gradle might report changes received since the last build even if you haven’t changed anything. These are harmless notifications about changes to Gradle’s own caches and can be ignored safely.
- Gradle does not pick up some of my changes
Please let us know on the Gradle community Slack if that happens to you. If your build declares its inputs and outputs correctly, this should not happen. So it’s either a bug we need to fix, or your build is lacking the declaration of some inputs or outputs.
- VFS state is dropped due to lost state
If you receive the
Dropped VFS state due to lost statemessage during the build, please let us know on the Gradle community Slack if that happens to you. This message means that either:
the daemon received some unknown file system event,
too many changes happened, and the watching API couldn’t handle it.
In both cases the build cannot benefit from file system watching.
- Too many open files on macOS
If you receive the
java.io.IOException: Too many open fileserror on macOS, you need to raise your open files limit, see here.
File system watching uses inotify on Linux. Depending on the size of your build, it may be necessary to increase inotify limits. If you are using an IDE, then you probably already had to increase the limits in the past.
File system watching uses one inotify watch per watched directory. You can see the current limit of inotify watches per user by running:
To increase the limit to e.g. 512K watches run the following:
echo 524288 | sudo tee -a /etc/sysctl.conf sudo sysctl -p --system
Each used inotify watch takes up to 1KB of memory. Assuming inotify uses all the 512K watches then around 500MB will be used for watching the file system. If your environment is memory constraint, you may want to disable file system watching.