skip to content

What makes a running daemon 'compatible' with an invocation? Which factors must match?

level: middleimportance: must knowfreq 50%

answer

  1. identity = JDK + JVM args + Gradle version
  2. immutable-at-launch settings (heap, encoding, GC)
  3. org.gradle.java.home / org.gradle.jvmargs
  4. drift -> daemon proliferation
  5. log level / task list don't affect identity

basics

~10 s

Compatibility is mainly about the JVM: the daemon must use the same Java home (JAVA_HOME) and have JVM arguments that satisfy the request. The Gradle version must also match.

solid answer

~40 s

A daemon's **identity** is defined by the JVM it runs on and its startup parameters. For reuse, the client checks that the daemon's **Java installation** (effectively `JAVA_HOME` / the resolved JDK) matches the one the build requires, and that its **JVM arguments** are compatible — heap settings like `-Xmx`, file encoding, and other immutable JVM flags. The **Gradle version** must match too (registries are per version). Settings that can only be applied at JVM launch — heap size, encoding, GC flags — cannot be changed in a live daemon, so a request needing different ones is incompatible and forces a new daemon. These parameters typically come from `org.gradle.java.home` and `org.gradle.jvmargs` in `gradle.properties`. If they drift between invocations, you get **daemon proliferation**: several daemons, each serving a different parameter set.

code

properties · 4 lines
properties
# gradle.properties — these define daemon identity
org.gradle.java.home=/opt/jdk-21
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8
# Changing either line forces the NEXT build onto a brand-new daemon

go deeper

for a junior

Know that the daemon must run the same Java and have matching JVM args/heap to be reused.

for a middle

Enumerate the identity factors (JDK, JVM args, version) and explain why launch-immutable settings force new daemons.

for a senior

Connect parameter drift to daemon proliferation and memory pressure; prescribe standardizing org.gradle.java.home / jvmargs.

for a principal

Govern JVM/toolchain identity org-wide so CI agents and developer machines converge on a single reusable daemon profile.

## What 'compatibility' means A daemon is a JVM that was launched once with a fixed set of startup parameters. Some of those parameters are **immutable for the life of the JVM** — you cannot change the maximum heap or the default file encoding of an already-running JVM. So the client must check, before reusing a daemon, that the daemon was started with parameters that satisfy the new request. That check is the **compatibility** test. ## The matching factors - **Java home / JDK** — the daemon runs on a specific Java installation. If the request needs a different `JAVA_HOME` (set via `org.gradle.java.home` or the toolchain that launches the daemon), the daemon is incompatible. This is the most common cause of a surprise new daemon. - **JVM arguments** — heap (`-Xmx`, `-Xms`), `-Dfile.encoding`, GC selection, `--add-opens`, and similar flags from `org.gradle.jvmargs`. Because these are JVM-launch-time settings, they must match. - **Gradle version** — the registry is keyed per version, so a daemon for 8.6 is never a candidate for an 8.7 build. ## Where the parameters come from These are usually declared in `gradle.properties` (project or `~/.gradle/`): ```properties org.gradle.java.home=/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8 ``` Change any of these and the next invocation cannot reuse the previous daemon; it spawns a new one with the new identity. The old one stays idle until it expires. ## Daemon proliferation If different builds (or different developers' shells with different `JAVA_HOME`) keep requesting different parameter sets, you accumulate many daemons, each holding its own heap. This wastes memory. The fix is to **standardize** the JDK and JVM args across the team so every invocation lands on one shared, reusable daemon. ## Not part of compatibility Runtime, per-build options that Gradle can apply *within* a build — log level, `--rerun-tasks`, the task list — are passed to the daemon for that build and do **not** affect identity. Only JVM-launch-immutable settings do.

  • Why can't a running daemon just switch to a larger heap to satisfy a request that needs -Xmx4g?
    Maximum heap is fixed at JVM launch and cannot be changed in a live process, so a request needing different heap is incompatible and forces a new daemon.
  • Do per-build flags like --info or --rerun-tasks make a daemon incompatible?
    No — those are applied within the build at runtime and don't affect the daemon's identity; only JVM-launch-immutable settings do.
  • What is daemon proliferation and how do you avoid it?
    Accumulating many daemons each serving a different JVM parameter set; avoid it by standardizing JAVA_HOME and org.gradle.jvmargs across the team.

saying these in an interview costs you the question

  • Saying the build script (build.gradle) content determines daemon compatibility.
  • Claiming a live daemon can adopt new heap or encoding settings on demand.
  • Treating log level / CLI task selection as identity parameters.

context