skip to content

An Apache JMeter run is started with JVM_ARGS="-Xmx4g" and HEAP left unset. What heap does the JVM get?

level: middleimportance: should knowfreq 52%

answer

  1. Two -Xmx flags on one line
  2. Order decides, nothing is removed
  3. Only what you repeat is superseded
  4. The initial size is left behind

basics

~10 s

Maximum 4 GB, initial still 1 GB. The launcher expands HEAP's default first and appends JVM_ARGS afterwards, so the later -Xmx4g wins while -Xms1g and -XX:MaxMetaspaceSize=256m stay on the line untouched.

solid answer

~40 s

`bin/jmeter` builds `ARGS` from `HEAP` and its siblings, then runs `java $ARGS $JVM_ARGS $JMETER_OPTS -jar ApacheJMeter.jar`. With `HEAP` unset the script still supplies `-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m`, and `-Xmx4g` from `JVM_ARGS` lands after it. The JVM honours the last `-Xmx`, so the maximum becomes 4 GB — but nothing was removed, so the initial heap is still 1 GB and the metaspace cap is still 256 MB. The manual's phrase that `JVM_ARGS` "will override the HEAP settings in the script" is true positionally, not substitutionally: it supersedes flags you repeat and leaves the rest alone. To move a whole injector past the shipped gigabyte, set the entire `HEAP` string instead of patching one flag.

code

bash · 11 lines
bash
$ JVM_ARGS="-Xmx4g" jmeter -n -t plan.jmx -l results.jtl

# bin/jmeter assembles, in this order:
#   ARGS="$JAVA_OPTS $SERVER $DUMP $HEAP $VERBOSE_GC $GC_ALGO ..."
#   "$JAVA_HOME/bin/java" $ARGS $JVM_ARGS $JMETER_OPTS -jar ApacheJMeter.jar "$@"
#
# effective line:  ... -Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m ... -Xmx4g ...
# effective heap:  initial 1g, maximum 4g, metaspace cap 256m

# Change the whole string instead, when you mean to change the heap:
$ export HEAP="-Xms4g -Xmx4g -XX:MaxMetaspaceSize=256m"

go deeper

for a junior

Recall that JMeter has two ways in: HEAP for the memory string and JVM_ARGS for extra java options. Knowing both variables exist and that JVM_ARGS comes last is enough at this level.

for a middle

Explain the assembly order in bin/jmeter and why a repeated flag supersedes rather than replaces. Say explicitly which flags survive untouched: -Xms and the metaspace cap.

for a senior

Show the operational consequence: a fleet patched with -Xmx alone runs with a mismatched initial and maximum heap. Verify with the Max memory line in jmeter.log rather than trusting the command you typed.

for a principal

Set the rule about which seam carries which kind of change: HEAP in setenv.sh for durable machine configuration, JVM_ARGS for one-off experiments and -D properties, and never a half-override that leaves the pair inconsistent.

## What the launcher actually assembles `bin/jmeter` in Apache JMeter 6.0.0 builds one string of JVM options and then appends the user's own: ```sh ARGS="$JAVA_OPTS $SERVER $DUMP $HEAP $VERBOSE_GC $GC_ALGO $SYSTEM_PROPS $JMETER_LANGUAGE $RUN_IN_DOCKER" "$JAVA_HOME/bin/java" $ARGS $JVM_ARGS $JMETER_OPTS -jar "$PRGDIR/ApacheJMeter.jar" "$@" ``` `HEAP` is expanded **inside** `ARGS`; `JVM_ARGS` comes **after** it. With `HEAP` left unset the script supplies its default, so the effective command line for `JVM_ARGS="-Xmx4g"` contains: ``` ... -Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m ... -Xmx4g ... ``` The JVM takes the last occurrence of a repeated `-Xmx`, so the maximum heap is **4 GB**. Nothing removed the earlier flags: `-Xms` is still `1g` and the metaspace cap is still `256m`. ## Why the manual calls that an override The Getting Started page says `JVM_ARGS` "will override most pre-defined settings" and that `JVM_ARGS="-Xms1024m -Xmx1024m" jmeter -t test.jmx` "will override the HEAP settings in the script". Read that precisely — the override is **positional, not substitutional**: - A flag you repeat in `JVM_ARGS` supersedes the one `HEAP` put on the line. - A flag you do **not** repeat is left exactly as `HEAP` set it. - Nothing warns you about the duplicate; the run starts normally. ## What that asymmetry costs An injector raised past its shipped gigabyte with only `-Xmx4g` starts at `-Xms1g` and grows toward `-Xmx4g`. JMeter ships `-Xms` and `-Xmx` equal for a reason and its own `setenv.sh` example keeps them equal (`export HEAP="-Xms1G -Xmx1G -XX:MaxMetaspaceSize=192m"`); a half-override quietly breaks that pairing. If you intend to change the heap rather than patch one flag, set the whole `HEAP` string: ```sh export HEAP="-Xms4g -Xmx4g -XX:MaxMetaspaceSize=256m" ``` ## Where each mechanism belongs | Mechanism | Scope | Use it when | |---|---|---| | `HEAP` in `bin/setenv.sh` | every run on that install | the machine is a dedicated injector | | `HEAP` exported for one command | that invocation | a one-off larger run | | `JVM_ARGS` on the command line | that invocation | adding `-D` properties, or patching a single JVM flag | | `JMETER_COMPLETE_ARGS` | that invocation | you want to supply the *entire* JVM line yourself | ## Verifying rather than assuming Two checks settle it without guessing: 1. Read `jmeter.log`. `org.apache.jmeter.JMeter` logs `Max memory =` at startup with `Runtime.getRuntime().maxMemory()` in bytes — about `4294967296` for four gigabytes. 2. Inspect the process arguments on the injector and count how many `-Xmx` flags are there. Seeing two is normal for this launcher, not a bug. The same layering applies on Windows: `bin/jmeter.bat` builds `ARGS` from `%HEAP%` and friends and then runs `"%JM_LAUNCH%" %ARGS% %JVM_ARGS% -jar ...`, so `JVM_ARGS` is appended last there too.

  • How would you prove which maximum heap the run actually used?
    Read `jmeter.log`. The startup block logged by `org.apache.jmeter.JMeter` includes `Max memory =` with `Runtime.getRuntime().maxMemory()` in bytes: about 4294967296 for four gigabytes, about 1073741824 if the override never took effect. Inspecting the running process's arguments works too, and seeing two `-Xmx` flags there is normal for this launcher.
  • Does the same ordering hold on Windows?
    Yes. `bin/jmeter.bat` builds `ARGS` from `%HEAP%`, `%GC_ALGO%` and the rest, then runs `"%JM_LAUNCH%" %ARGS% %JVM_ARGS% -jar "%JMETER_BIN%ApacheJMeter.jar"`. `JVM_ARGS` is appended last there as well, so a repeated flag in it supersedes the launcher's own in exactly the same way.

Like a checklist where a later entry crosses out an earlier one: the launcher writes -Xmx1g first and your -Xmx4g after it, and the reader acts on the last line rather than on the whole page.

saying these in an interview costs you the question

  • Says JVM_ARGS replaces the whole HEAP string
  • Expects a duplicate -Xmx to fail the run
  • Assumes the initial heap follows the new maximum
  • Puts JVM_ARGS before ARGS in the command line
  • Thinks the metaspace cap scales with -Xmx