skip to content

Daemon JVM Tuning

Sizing and controlling the JVM that runs Gradle itself: heap and metaspace, idle timeout, which JDK it uses, and when to switch it off entirely. Interviewers ask because daemon memory is a recurring cause of mysterious build failures.

on this pageshow

questions

20

What does the Gradle daemon do, and how do you disable it for a single build invocation?

level: juniorimportance: must knowfreq 60%

answer

  1. long-lived background JVM
  2. --no-daemon = single-use
  3. org.gradle.daemon=false
  4. --status / --stop
  5. warm JIT, cached config

basics

~10 s

The daemon is a long-lived background JVM that Gradle reuses across builds to avoid startup cost. Disable it for one build with --no-daemon, or permanently via org.gradle.daemon=false in gradle.properties.

solid answer

~40 s

The Gradle **daemon** is a persistent background JVM process that stays alive between invocations, keeping the JVM warm (JIT-compiled code), caching build configuration, and avoiding repeated JVM and Gradle bootstrap cost. Each build normally connects to a compatible idle daemon or spawns a new one. To disable it for a single run, pass `--no-daemon` on the command line: ``` ./gradlew build --no-daemon ``` That build runs in a **single-use** daemon: a foreground process that exits as soon as the build finishes. To disable it persistently, set `org.gradle.daemon=false` in `gradle.properties` (project or `~/.gradle/`), or export `GRADLE_OPTS="-Dorg.gradle.daemon=false"`. Conversely `--daemon` forces daemon use for one build.

code

bash · 9 lines
bash
# disable for one build
./gradlew build --no-daemon

# disable persistently
echo 'org.gradle.daemon=false' >> gradle.properties

# inspect / stop running daemons
./gradlew --status
./gradlew --stop

go deeper

for a junior

Know that the daemon is a reused background process and that --no-daemon / org.gradle.daemon=false turn it off.

for a middle

Explain the single-use daemon nuance, the three ways to disable, and precedence between flag and property.

for a senior

Tie disabling to JIT/warm-up trade-offs and know --status/--stop for diagnosing daemon state.

for a principal

Frame daemon-on vs daemon-off as a policy choice per environment (dev vs CI) and standardise it across teams.

## What the daemon is The **Gradle daemon** is a long-lived JVM process that Gradle launches in the background. Running a build via the launcher (`gradle`/`gradlew`) starts a thin client process that hands the work to a daemon. The daemon stays resident after the build ends so the *next* build can reuse it. ## Why a daemon exists Starting a fresh JVM is expensive: classloading, JIT warm-up, and Gradle's own bootstrap (loading plugins, building the model). By keeping a warm JVM around, the daemon: - skips JVM start-up on subsequent builds - benefits from **JIT** optimisation accumulated across builds (hot code is compiled to native) - keeps in-memory caches warm (e.g. resolved configuration) This is why a second build is usually much faster than the first. ## How to disable it There are three equivalent levers, from most to least scoped: 1. **Per-invocation flag** — `--no-daemon` (or its inverse `--daemon`). 2. **Property in `gradle.properties`** — `org.gradle.daemon=false` (project-level `gradle.properties` or the user-level `~/.gradle/gradle.properties`). 3. **JVM system property via env** — `GRADLE_OPTS="-Dorg.gradle.daemon=false"`. Precedence: a command-line flag wins over a property, and project properties layer with user-level ones. ## Single-use daemon `--no-daemon` does **not** mean "no JVM forked." Gradle still forks a worker JVM, but it runs as a **single-use daemon**: it executes exactly one build in the foreground and then terminates. So you still pay JVM start-up once, but nothing survives the build — no resident process, no cross-build reuse. ```bash # one build, no surviving process ./gradlew test --no-daemon # inspect / clean up daemons ./gradlew --status ./gradlew --stop ``` `--status` lists running daemons and their states (IDLE, BUSY); `--stop` gracefully shuts them down. ## Mental model Daemon = warm, reusable, fast for repeated local builds. `--no-daemon` = cold, single-shot, predictable for one-off and CI builds where nothing should outlive the job.

  • Does --no-daemon mean no separate JVM is forked at all?
    No. Gradle still forks a JVM, but it runs as a single-use daemon that executes exactly one build in the foreground and then exits, so nothing survives the build.
  • How do you see whether daemons are currently running?
    `./gradlew --status` lists running daemons with their PID and state (IDLE/BUSY); `./gradlew --stop` shuts them down gracefully.

A daemon is like leaving your car engine running between short errands so you skip the cold start each time; --no-daemon is turning the engine off completely after one trip.

saying these in an interview costs you the question

  • Claiming --no-daemon runs the build inside the launcher with no forked JVM at all.
  • Saying the daemon is just a thread inside the gradlew client rather than a separate process.

context

open as a page

What does the org.gradle.daemon.idletimeout property control, and what is its default?

level: juniorimportance: must knowfreq 45%

basics

~10 s

It sets how long (in milliseconds) an idle Gradle daemon stays alive before shutting itself down. The default is 10800000 ms — three hours.

open as a page

What is org.gradle.jvmargs and where do you set it to control the Gradle daemon's heap?

level: juniorimportance: must knowfreq 62%

basics

~10 s

org.gradle.jvmargs is a Gradle property that passes JVM flags (like -Xmx) to the build daemon's JVM. You set it in gradle.properties, usually in the project root or the user's ~/.gradle directory.

open as a page

What is the difference between the JVM that runs the Gradle daemon and the JVM used by Java toolchains for compiling and testing your code?

level: juniorimportance: must knowfreq 55%

basics

~10 s

The daemon JVM is the JVM that actually runs Gradle itself. Java toolchains pick a (possibly different) JDK to compile and run your project's code. They are configured separately and can be different versions.

open as a page

Why is disabling (or constraining) the Gradle daemon a common recommendation on ephemeral CI agents?

level: middleimportance: must knowfreq 65%

basics

~10 s

On throwaway CI agents the daemon never gets reused, so it brings no speed-up but risks orphaned processes and memory bloat. Disabling it gives a clean, predictable single-use JVM per job.

open as a page

A large multi-module build fails with 'java.lang.OutOfMemoryError: Java heap space' during configuration/compilation. How do you diagnose and fix it via the daemon JVM args?

level: middleimportance: must knowfreq 55%

basics

~10 s

Confirm the OOM is in the daemon (not a forked test worker), then raise the daemon heap in gradle.properties via org.gradle.jvmargs=-Xmx (e.g. -Xmx3g) and add -XX:+HeapDumpOnOutOfMemoryError to capture a dump if it recurs.

open as a page

What is the Daemon JVM Criteria (gradle/gradle-daemon-jvm.properties), how do you generate it, and what problem does it solve?

level: middleimportance: must knowfreq 40%

basics

~20 s

It's a committed file declaring the version/vendor of the JDK that should run the Gradle daemon. You generate it with ./gradlew updateDaemonJvm. It makes the daemon JVM reproducible across machines instead of relying on a path or JAVA_HOME.

open as a page

A repo's gradle.properties has org.gradle.daemon=true but CI runs ./gradlew build --no-daemon. What happens, and how should you manage these settings across local and CI?

level: middleimportance: should knowfreq 30%

basics

~20 s

The command-line --no-daemon wins for that build — it runs single-use despite the property. Best practice: leave the property at the developer-friendly default and let CI override per-invocation, or set it via a user-level/env config in CI.

open as a page

How do you inspect which Gradle daemons are alive and in what state, and how do you force them to stop? When would you reach for each command?

level: middleimportance: should knowfreq 38%

basics

~10 s

gradle --status lists live daemons with their PID, Gradle version and status (IDLE/BUSY). gradle --stop terminates all daemons for that Gradle version. Use --status to inspect, --stop to clear stale/misbehaving daemons immediately.

open as a page

On a memory-constrained or shared CI agent, how would you tune the daemon idle timeout, and what trade-off are you making?

level: middleimportance: should knowfreq 40%

basics

~10 s

Lower org.gradle.daemon.idletimeout (e.g. to 1–5 minutes) so idle daemons exit fast and release their heap. The trade-off: more cold starts, so slightly slower first builds.

open as a page

How does org.gradle.java.home work, where can you set it, and what are its drawbacks compared to newer mechanisms?

level: middleimportance: should knowfreq 45%

basics

~10 s

org.gradle.java.home is a Gradle property holding an absolute path to the JDK that should run the daemon. You set it in gradle.properties (or via -D). Its drawback: the path is machine-specific and not portable.

open as a page

A self-hosted runner pool reuses agents across many Gradle jobs. How do you decide whether to disable or keep (but constrain) the daemon?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Measure reuse. If agents run many back-to-back Gradle builds, keeping the daemon speeds them up — but cap its memory and prevent accumulation. If reuse is rare or limits are tight, disable it for predictability.

open as a page

Even with the daemon disabled, how can Gradle leave processes behind on a CI agent, and how do you ensure a clean exit?

level: seniorimportance: should knowfreq 40%

basics

~20 s

A build forks more than the main JVM — worker daemons for compilation/tests. With the build daemon disabled you still want these to exit; use --no-daemon plus killing stray Java processes or running in a destroyed-per-job container.

open as a page

Why might Gradle start a brand-new daemon and leave the old one idle even though one was already warm? How does idletimeout relate to that stale daemon?

level: seniorimportance: should knowfreq 35%

basics

~20 s

A daemon's JVM args and JDK are fixed at startup. If a build requests incompatible args (different heap, JDK, etc.), Gradle can't reuse the warm daemon, so it starts a fresh one. The old daemon sits idle and is only reclaimed when its idletimeout expires.

open as a page

How do you choose org.gradle.jvmargs heap/metaspace values across local machines and CI agents, and what trade-offs guide the numbers?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Commit a sane baseline in the project gradle.properties that fits the smallest target (CI agent), and let powerful dev machines bump it via ~/.gradle/gradle.properties. Size so daemon heap plus forked workers fit RAM, leaving OS headroom.

open as a page

What is metaspace, why do long-lived Gradle daemons hit 'OutOfMemoryError: Metaspace', and how does MaxMetaspaceSize fit into the fix?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Metaspace is native memory holding class metadata. A reused daemon loads classes across many builds; leaked classloaders accumulate metadata until 'OutOfMemoryError: Metaspace'. Set -XX:MaxMetaspaceSize to a sane cap (and fail fast with a dump) rather than leaving it unbounded.

open as a page

A teammate sets org.gradle.java.home to a JDK that doesn't meet Gradle's requirements (too old, or a JRE), and the build fails. How do you diagnose and resolve daemon-JVM-selection problems like this?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Check which JVM the daemon is actually using (./gradlew --version or buildEnvironment), verify it meets Gradle's supported range and is a full JDK, then fix the selection via org.gradle.java.home, the criteria file, or JAVA_HOME — and remove stale daemons.

open as a page

Besides -Xmx, what other JVM flags are commonly worth putting in org.gradle.jvmargs, and what is Gradle's default if you set nothing?

level: middleimportance: nice to knowfreq 26%

basics

~10 s

If unset, Gradle uses a modest default heap (historically 512m, 1g in recent versions). Beyond -Xmx, common additions are -XX:MaxMetaspaceSize, -XX:+HeapDumpOnOutOfMemoryError, -Dfile.encoding=UTF-8, and sometimes -XX:+UseParallelGC or other GC/locale/encoding flags.

open as a page

What happens if you set org.gradle.daemon.idletimeout to 0 (or a very small value)? Is that the same as disabling the daemon?

level: seniorimportance: nice to knowfreq 22%

basics

~20 s

Setting idletimeout to 0 (or tiny) means the daemon shuts down almost as soon as it goes idle — so you lose warm reuse between builds. It is NOT the same as disabling the daemon: a daemon still forks, runs your build, then exits.

open as a page

Across many repositories and a CI fleet, how would you standardize and govern the JVM that runs Gradle (the daemon JVM) without breaking individual contributors?

level: principalimportance: nice to knowfreq 18%

basics

~10 s

Commit a Daemon JVM Criteria file per repo to pin version/vendor, configure toolchain provisioning/repositories for CI, ban committed org.gradle.java.home paths, and allow personal overrides only in ~/.gradle. This gives reproducibility while keeping local flexibility.

open as a page