How do you pass custom JVM and -XX flags to the test JVM in Gradle, and what's the difference between assigning and appending them?
answer
- jvmArgs(...) appends, jvmArgs = ... replaces
- Test implements JavaForkOptions
- -XX tuning, -ea, -javaagent per worker
- don't mix maxHeapSize with -Xmx jvmArg
- each fork gets the same args
basics
~10 sOn the test task use jvmArgs(...) to add flags like -XX:+HeapDumpOnOutOfMemoryError. Calling jvmArgs("-X...") appends; assigning jvmArgs = listOf(...) replaces the whole list. Heap shortcuts use minHeapSize/maxHeapSize.
solid answer
~40 sThe `test` task exposes `jvmArgs` for arbitrary flags passed to each forked test worker — `-XX` tuning flags, GC selection, `-ea`, agent attachment, etc. There are two forms: the **method** `jvmArgs("-XX:+UseG1GC", "-ea")` *appends* to the existing list, while the **property assignment** `jvmArgs = listOf(...)` *replaces* it wholesale (and would wipe anything Gradle or plugins added). Prefer the append form unless you deliberately want a clean slate. Heap-specific flags have idiomatic shortcuts (`maxHeapSize`/`minHeapSize`) — using those instead of raw `-Xmx`/`-Xms` keeps configuration readable and avoids duplicate conflicting flags. All of this is per forked worker, so each parallel fork receives the same args.
code
kotlin · 9 linestasks.test {
maxHeapSize = "2g" // prefer this over -Xmx jvmArg
jvmArgs( // append form
"-XX:+UseG1GC",
"-XX:+HeapDumpOnOutOfMemoryError",
"-ea",
)
// jvmArgs = listOf("-ea") // BEWARE: this would replace everything above
}go deeper
Know jvmArgs(...) adds flags to the test JVM and heap has its own shortcuts.
Crisply distinguish the appending method call from the replacing property assignment; avoid duplicate heap flags.
Anticipate per-worker collisions (heap dump paths) and plugin-added flags being wiped by assignment; verify the launched command line.
Codify a standard test-JVM flag set in a convention plugin; forbid blind reassignment to keep org-wide diagnostics flags intact.
## jvmArgs on the Test task The `Test` task implements `JavaForkOptions`, which gives it a mutable `jvmArgs` list applied to **every** forked test worker. You use it for anything you'd otherwise type on a `java` command line: - GC / tuning: `-XX:+UseG1GC`, `-XX:MaxMetaspaceSize=512m` - Diagnostics: `-XX:+HeapDumpOnOutOfMemoryError`, `-XX:HeapDumpPath=...` - Assertions: `-ea` (enable assertions) - Agents: `-javaagent:/path/agent.jar`, `-XX:+EnableDynamicAgentLoading` - Preview features: `--enable-preview` ## Append vs replace — a real footgun ```kotlin tasks.test { jvmArgs("-XX:+HeapDumpOnOutOfMemoryError") // APPENDS jvmArgs = listOf("-ea") // REPLACES the whole list } ``` The **method call** `jvmArgs(...)` adds to whatever is already there. The **assignment** `jvmArgs = ...` throws the existing list away. If a plugin or earlier configuration added important flags, an assignment silently drops them. As a rule, append unless you intend a reset. ## Don't duplicate heap flags Gradle gives `minHeapSize`/`maxHeapSize` as dedicated properties. Mixing `maxHeapSize = "2g"` with `jvmArgs("-Xmx1g")` produces two `-Xmx` flags; the JVM honors the last one, which is fragile and confusing. Pick one mechanism for heap. ## Inspecting what was actually passed Because workers are separate processes, add `-XX:+PrintFlagsFinal` or run with `--info` to see the launched command line when a flag seems ignored. ## Per-worker, not shared Every flag in `jvmArgs` is applied to each forked worker independently. With multiple forks, a flag like a fixed `-XX:HeapDumpPath` to a single file can collide — parameterize paths per worker if needed.
- You wrote `jvmArgs = listOf("-ea")` and a profiler agent flag added by a plugin vanished. Why?Assigning to jvmArgs replaces the entire list, discarding flags added earlier. Use the append form `jvmArgs("-ea")` so the plugin's `-javaagent` survives.
- A flag you added seems ignored. How do you confirm what the worker actually launched with?Run with --info to see the worker command line, or add -XX:+PrintFlagsFinal; remember each fork is a separate process so check the right one.
saying these in an interview costs you the question
- Thinking `jvmArgs = listOf(...)` appends — it replaces.
- Setting both maxHeapSize and a raw -Xmx jvmArg.
- Assuming jvmArgs on test affects the daemon or compilation.