Next Practical Step
Audit all JSR223 elements to replace \${var} interpolation with vars.get("var") and verify that script caching is enabled.
Fix JMeter OutOfMemoryError: Metaspace and GC overhead limit exceeded. Prevent Groovy compilation leaks, tune JVM GC, and configure MaxMetaspaceSize.
During execution or extended soak tests, JMeter crashes with one of these JVM OutOfMemory errors in jmeter.log or console:
java.lang.OutOfMemoryError: Metaspace at java.lang.ClassLoader.defineClass1(Native Method) at groovy.lang.GroovyClassLoader.createSubClass(GroovyClassLoader.java:940)Or when garbage collection takes up nearly 100% of CPU time with minimal memory recovered:
java.lang.OutOfMemoryError: GC overhead limit exceeded at org.apache.jmeter.threads.JMeterVariables.put(JMeterVariables.java:95)Throughput drops to near zero, response times spike dramatically, and the load generator CPU spikes to 100% due to continuous full garbage collection cycles.
OutOfMemoryError: Metaspace: The JVM class metadata area is exhausted. The most common cause is embedding \${var} variable interpolation inside JSR223 Groovy scripts, forcing the Groovy runtime to compile a brand-new Java class on every execution.GC overhead limit exceeded: Java spent more than 98% of its total CPU time performing garbage collection and recovered less than 2% of the heap.| Cause | Error | Why it happens |
|---|---|---|
In-script string interpolation (\${var}) | Metaspace | Using vars.get("x") vs "Hello ${x}" avoids generating millions of temporary dynamic classes that fill Metaspace |
| Unchecked “Cache compiled script” | Metaspace / CPU | JSR223 elements re-parse and compile script source on every single sample execution |
| Small default Metaspace cap | Metaspace | JVM default -XX:MaxMetaspaceSize is too constrained for large test plans with many plugins |
| Heavy listener memory retention | GC Overhead | Listeners (View Results Tree, Graph Results) retaining millions of SampleResult objects in heap |
| Large in-memory file buffers | GC Overhead | Reading large CSV files or response bodies entirely into Groovy script memory variables |
Never embed \${variable_name} directly inside JSR223 Groovy code. Groovy treats the script text as a template and generates a new class file every time the variable changes:
// ❌ WRONG: Leaks Metaspace and exhausts compilation cache!String token = "${auth_token}";log.info("Processing user ${user_id}");
// ✅ CORRECT: Reuses compiled class, zero Metaspace growthString token = vars.get("auth_token");log.info("Processing user " + vars.get("user_id"));In every JSR223 PreProcessor, JSR223 PostProcessor, JSR223 Sampler, and JSR223 Assertion:
groovy (Groovy ... / Groovy Scripting Engine).<!-- Correct JSR223 configuration in JMX --><JSR223Sampler guiclass="TestBeanGUI" testclass="JSR223Sampler" testname="Process Data"> <stringProp name="scriptLanguage">groovy</stringProp> <stringProp name="parameters"></stringProp> <stringProp name="filename"></stringProp> <stringProp name="cacheKey">true</stringProp> <stringProp name="script">String id = vars.get("userId");vars.put("processedId", id.toUpperCase());</stringProp></JSR223Sampler>Set explicit Metaspace and Heap sizing in your launch environment:
# Linux / macOS environment variablesexport JVM_ARGS="-Xms4g -Xmx4g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+UseG1GC"jmeter -n -t test.jmx -l results.jtl -j jmeter.log@REM Windows bin/jmeter.bat or set in terminalset JVM_ARGS=-Xms4g -Xmx4g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+UseG1GCjmeter.bat -n -t test.jmx -l results.jtlDuring load tests, disable all visual listeners:
-l results.jtl) and generate the HTML dashboard after the test completes (dashboard guide).Ensure modern G1GC settings are configured for low pause times:
# Recommended JVM arguments for high-throughput JMeter testing-XX:+UseG1GC-XX:MaxGCPauseMillis=100-XX:G1ReservePercent=15-XX:InitiatingHeapOccupancyPercent=45| Resource | Use when |
|---|---|
| OutOfMemoryError heap | Standard Java heap memory troubleshooting |
| JSR223 Groovy script errors | Resolving Groovy scripting exceptions |
| Heap Estimator | Sizing JVM heap and Metaspace memory |
| Best practices | Official performance tuning guidelines |
Metaspace lives in native memory outside the Java heap. If Groovy compiles new classes dynamically (due to \${var} string interpolation), these classes are loaded into Metaspace and are rarely garbage collected unless classloaders are completely unloaded.
Heap OOM means Java objects (byte arrays, strings, collections) filled -Xmx. Metaspace OOM means loaded class metadata filled -XX:MaxMetaspaceSize.