A JMeter injector started via bin/jmeter.sh ignores the HEAP you set. What does that script do differently?
answer
- One wrapper delegates to the other
- A variable empties the whole option block
- Only two variables survive to java
- The heap-dump flag goes with it
basics
~10 sIt exports JMETER_COMPLETE_ARGS=true before calling bin/jmeter, which makes that script set ARGS empty. Only JVM_ARGS and JMETER_OPTS then reach java, so HEAP, GC_ALGO and the OOM heap-dump flag are all dropped.
solid answer
~40 sApache JMeter ships `bin/jmeter.sh` as a deliberately minimal wrapper — the manual calls it a "very basic JMeter script (You may need to adapt JVM options like memory settings)". It sets `JMETER_COMPLETE_ARGS=true`, folds the `--add-opens` list into `JVM_ARGS`, exports both, and delegates to `bin/jmeter`. There, a non-empty `JMETER_COMPLETE_ARGS` takes the `else` branch and sets `ARGS=""`, so `HEAP`, `GC_ALGO`, `VERBOSE_GC`, `-server`, `-Djava.security.egd=file:/dev/urandom`, the language flags and `-XX:+HeapDumpOnOutOfMemoryError` never reach `java`. The manual states the same contract: `JVM_ARGS` and `JMETER_OPTS` are used "only", and "all other options like `HEAP` and `GC_ALGO` will be ignored". Nothing errors, so an injector you believed was raised past its gigabyte quietly runs on the JVM's own defaults.
code
bash · 12 lines# bin/jmeter.sh, last lines
JMETER_COMPLETE_ARGS=true
JVM_ARGS="$JAVA9_OPTS $JVM_ARGS"
export JVM_ARGS JMETER_COMPLETE_ARGS
"${PRGDIR}/jmeter" "$@"
# bin/jmeter, where that lands
if [ -z "${JMETER_COMPLETE_ARGS}" ]; then
ARGS="$JAVA_OPTS $SERVER $DUMP $HEAP $VERBOSE_GC $GC_ALGO $SYSTEM_PROPS $JMETER_LANGUAGE $RUN_IN_DOCKER"
else
ARGS=""
figo deeper
Recall that JMeter ships more than one start script and that bin/jmeter is the full one. If you are setting HEAP, launch through bin/jmeter.
Explain the mechanism: JMETER_COMPLETE_ARGS makes bin/jmeter set ARGS empty, leaving only JVM_ARGS and JMETER_OPTS, and bin/jmeter.sh sets that variable for you.
Demonstrate the diagnosis. The failure is silent, so name the evidence: compare the Max memory line in each injector's jmeter.log against the heap you configured, and enumerate what else was dropped.
Decide the fleet policy. Either standardise on bin/jmeter plus setenv.sh, or own the whole JVM line through JMETER_COMPLETE_ARGS and re-supply the heap-dump and module-access flags explicitly.
## Two scripts, one of them deliberately bare Apache JMeter 6.0.0 ships both `bin/jmeter` and `bin/jmeter.sh`, and the user manual describes the second as a "very basic JMeter script (You may need to adapt JVM options like memory settings)". That parenthesis is the whole behaviour. `bin/jmeter.sh` is a wrapper: it checks the Java version, builds the `--add-opens` list, and then does this before delegating: ```sh JMETER_COMPLETE_ARGS=true JVM_ARGS="$JAVA9_OPTS $JVM_ARGS" export JVM_ARGS JMETER_COMPLETE_ARGS "${PRGDIR}/jmeter" "$@" ``` ## What JMETER_COMPLETE_ARGS does downstream `bin/jmeter` branches on it: ```sh if [ -z "${JMETER_COMPLETE_ARGS}" ]; then ARGS="$JAVA_OPTS $SERVER $DUMP $HEAP $VERBOSE_GC $GC_ALGO $SYSTEM_PROPS $JMETER_LANGUAGE $RUN_IN_DOCKER" else ARGS="" fi ``` `ARGS` is emptied, so only `$JVM_ARGS $JMETER_OPTS` survive onto the `java` line. The manual states it in the same terms: "If set indicates, that `JVM_ARGS` and `JMETER_OPTS` are to be used, only. All other options like `HEAP` and `GC_ALGO` will be ignored." Everything below is dropped in that path: - `HEAP` — so the exported `-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m`, or whatever you raised it to, never appears. - `GC_ALGO` — `-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:G1ReservePercent=20`. - `DUMP` — `-XX:+HeapDumpOnOutOfMemoryError`, which `bin/jmeter` otherwise sets unconditionally. - `SERVER` (`-server`), `SYSTEM_PROPS` (`-Djava.security.egd=file:/dev/urandom`), `JMETER_LANGUAGE`, `VERBOSE_GC`. Only the module-access flags survive, because `bin/jmeter.sh` smuggles them through `JVM_ARGS` rather than through `ARGS`. ## Why the symptom looks like "HEAP is ignored" The failure is silent by construction. Nothing errors; the run starts, the plan executes, and the injector simply carries the JVM's own default maximum heap instead of yours. On a machine whose defaults happen to be generous the run may even look fine, and the discrepancy only surfaces when someone compares two generators. ## Diagnosing it in one step `org.apache.jmeter.JMeter` logs a startup block at INFO containing `java.version=`, `java.vm.name=` and `Max memory =` with `Runtime.getRuntime().maxMemory()` in bytes. Compare that number across your injectors: 1. Machines launched through `bin/jmeter` show the heap `HEAP` asked for. 2. Machines launched through `bin/jmeter.sh` — or through anything that exports `JMETER_COMPLETE_ARGS` — show the JVM's own default instead. 3. A run raised past the shipped gigabyte that still reports roughly `1073741824` was launched with the shipped default, not with yours. ## Using it on purpose `JMETER_COMPLETE_ARGS` is a legitimate switch, not only a trap: it is how you take full control of a generator's JVM line, for instance from a wrapper that already knows the machine's memory. The contract is all-or-nothing — if you set it, you own the heap flags, the collector flags, the `--add-opens` list and `-XX:+HeapDumpOnOutOfMemoryError` yourself, and you should re-supply anything you still want. Where you have no such wrapper, prefer `bin/jmeter` plus `bin/setenv.sh`, which is the combination the launcher is written for.
- How would you spot this across a fleet of generators without reading each launcher?Compare the `Max memory =` line that `org.apache.jmeter.JMeter` writes at INFO into each engine's `jmeter.log`; it carries `Runtime.getRuntime().maxMemory()` in bytes. Machines launched through `bin/jmeter` report the heap you configured, and machines that picked up `JMETER_COMPLETE_ARGS` report the JVM's own default instead.
- Is JMETER_COMPLETE_ARGS ever the right thing to set deliberately?Yes, when a wrapper already computes the entire JVM line — for example one that sizes the heap from the machine. The contract is all-or-nothing: you then own the heap flags, the collector flags, the `--add-opens` list and `-XX:+HeapDumpOnOutOfMemoryError` yourself, and must re-supply anything you still want.
- Which flags does bin/jmeter.sh still manage to pass through?Only the module-access options. It prepends the `--add-opens` list to `JVM_ARGS` rather than relying on `ARGS`, so those survive the emptying. Everything the launcher normally contributes through `ARGS` — heap, collector, `-server`, the entropy source, the language flags and the heap-dump switch — does not.
saying these in an interview costs you the question
- Assumes bin/jmeter.sh is just an alias for bin/jmeter
- Expects an error or warning when HEAP is ignored
- Thinks JMETER_COMPLETE_ARGS only affects GC_ALGO
- Believes the OOM heap dump is always armed
- Reports the intended heap from the launch command