Chapter 26Lesson 03~215 minutes

Load Generator Sizing, JVM Tuning, OS Limits, and Network Capacity: Configuration, Design Patterns, and Trade-Offs

Generator tuning is not a checklist of “magic JVM flags.” Each intervention changes one layer of the load-generation system and can also change realism. The correct choice is the smallest change that removes a measured injector constraint without changing the workload question you meant to ask.

Vertical vs horizontalHeap vs allocationConnection reuseDNS strategyOS limits

Learning objectives

  • Choose vertical sizing versus additional engines from measured resource saturation.
  • Choose heap growth versus lower object allocation/live-set pressure.
  • Choose connection reuse versus deliberate churn based on modeled client behavior.
  • Choose DNS caching strategy without contaminating a capacity benchmark.
  • Choose OS tuning only when a measured limit is genuinely binding.
  • Choose lean JTL or richer diagnostics according to phase and overhead budget.

1. Mandatory design path stays local/free

No privileged tuning is required. The executable path remains 127.0.0.1:8026 with JDK/JMeter/OS read-only inspection and a JMX keep-alive toggle. Managed load clouds, paid APM, commercial OS tooling, shared performance farms and managed Kubernetes are optional contexts only.

2. Larger generator versus more engines

Vertical sizing More engines
Add CPU/RAM/NIC/storage to one injector when one resource is clearly limiting and the OS/JVM can use the headroom. Split workload across independently measured engines when one host cannot maintain required headroom.
Simpler artifacts/network topology. More inventory, data sharding, clocks and orchestration—Chapter 25 contracts apply.
Still has one host/NIC/kernel failure domain. Reduces one-host bottleneck but total controller/backend/SUT network paths grow.
Best after proving which resource scales with hardware. Best after per-engine usable capacity is measured.

Do not add engines merely because “JMeter supports distributed mode.” Horizontal scaling preserves validity only if each engine receives an intentional share and the aggregate target/network path can support the sum.

3. More heap versus less object creation

Increasing -Xmx can help when live set legitimately exceeds available heap and GC/OOM is the measured constraint. It does not fix:

  • View Results Tree/body retention;
  • unbounded variables/results stored in Groovy;
  • huge in-memory datasets;
  • high-cardinality caches;
  • unnecessary XML/JSON parsing;
  • a CPU-bound plan.

First remove avoidable object retention/allocation, then size heap with observed live-set/GC headroom. A giant heap can make rare full collections or dumps more disruptive and increases host memory commitment.

4. GC tuning is a JVM experiment, not a copied blog snippet

JMeter's current launcher uses G1GC defaults. Keep that baseline unless measured GC behavior justifies a controlled change. Record the exact Java build and flags, then compare the same JMX/workload. Do not mix heap/collector/OS/network changes in one test.

5. Connection reuse versus socket churn

Keep-alive reduces handshakes/local-port/TIME_WAIT pressure, but realism matters. If the real client reuses persistent HTTP connections, disabling reuse makes the generator less realistic and more expensive. If the real system deliberately creates short-lived connections, keeping them alive merely to “make JMeter faster” would model the wrong protocol behavior.

Current HttpClient4 TTL is 60 seconds by default; validate connection lifecycle against the application/load balancer rather than assuming infinite reuse.

6. Local/JVM DNS caching strategy

Strategy Use when Trade-off
Benchmark by stable IP Generator capacity experiment should exclude DNS. Does not represent hostname/LB DNS behavior.
Default JVM DNS cache Ordinary applications where Java resolver behavior is acceptable. May keep one resolved IP longer than desired for DNS-balanced targets.
DNS Cache Manager + HttpClient4 Need thread/iteration-specific/custom/static DNS behavior. Adds resolver work/config and changes target IP distribution.
Flush/change global OS/JDK DNS settings Only an explicitly authorized isolated experiment. High blast radius; not part of mandatory path.

7. OS tuning versus simpler workload design

Examples of measured OS constraints include a low POSIX FD limit, exhausted local TCP port range, kernel socket buffer pressure or NIC saturation. But first ask whether the plan is creating unnecessary sockets/files/listener output. Fixing connection reuse/result verbosity can be more portable and safer than privileged kernel changes.

If an OS change is genuinely required, treat it as infrastructure-as-code: exact old/new value, authorization, host scope, restart requirement, validation and rollback command.

8. Firewall/antivirus changes are not normal performance “tuning”

Security software can affect CPU/file/network behavior, but disabling it on an unmanaged/shared workstation changes the security boundary and may violate policy. Use a dedicated authorized generator image/exception designed by the responsible security/IT team, then compare evidence. Do not turn off protection ad hoc to improve a score.

9. Lean JTL versus verbose diagnostics

Lean CSV is the load profile; rich XML/body/header diagnostics belong to tiny reproductions. If you need response correctness at scale, prefer assertions/failure messages/target telemetry over saving every response body. Chapter 22's result contract remains in force.

10. HTTP client defaults that affect generator capacity

  • Default implementation: HttpClient4.
  • Default retry count: 0—do not add retries to hide socket/connect failures.
  • Connection TTL: 60 seconds by current property default.
  • Use KeepAlive works with HttpComponents and changes connection reuse.
  • For very large response downloads, HTTP Request can save only an MD5 digest rather than retaining the response body in the SampleResult; use only if body content is not needed by extractors/assertions.

11. Configuration-layer boundaries

Layer Examples Do not confuse with
JMeter core/test plan threads, listeners, keepalive, DNS Cache Manager, assertions, save fields JVM heap/GC.
Java/JVM HEAP, G1GC, allocation/GC/JIT kernel local-port/FD limits.
OS/network handles/FDs, ephemeral ports, DNS resolver, NIC, disk/filesystem target CPU/DB saturation.
SUT service processing, connection limits, LB, database/cache generator connection/TIME_WAIT pressure.
Plugin/driver custom samplers, JDBC/JMS client libs core HttpClient4 behavior.
CI/container/orchestrator CPU/memory quotas, overlay disk, virtual network/DNS bare-metal generator capacity.

12. Worked scenario

A generator shows: 92% process CPU, low heap occupancy/GC time, 30 established sockets, low disk/NIC utilization, stable target service time. Would adding heap fix capacity?

No. CPU is the measured dominant resource. First reduce CPU-heavy plan work (scripts/parsers/listeners) or add CPU/engines. Heap tuning does not create CPU cycles.

13. Decision table

Observed constraint First design response When to scale/tune further
GC/heap pressure remove retention/allocation; then measured heap increase if live set legitimately needs more heap and host RAM has headroom.
CPU saturation simplify CPU-heavy plan / use compiled Groovy / add CPU if workload realism requires the work.
Socket/local-port churn reuse connections when realistic; check retries/TLS/DNS OS port tuning only after realistic connection model still exhausts range.
FD/handle limit remove leaks/unnecessary files/sockets; inspect limit raise isolated host limit with rollback only if required concurrency is valid.
NIC saturation reduce unnecessary payload/result/backend traffic or add NIC/engines when target workload truly requires those bytes.
Disk/JTL pressure lean CSV / fewer fields / separate debug artifacts faster/local storage when evidence contract still requires volume.
DNS latency measure/cache/model resolver behavior custom DNS only when production behavior requires it.

14. Evidence contract for generator-sizing comparisons

Every before/after sizing or tuning comparison must retain the source CSV JTL, the matching jmeter.log, exact JMX/property/JVM settings, hardware/OS inventory, JVM heap/GC snapshots, process CPU, socket/FD/handle state, NIC/disk evidence, and independent target service/count evidence. A tuning result without the original generator-state evidence is not reproducible.

15. Usable-capacity definition

Define a generator-specific gate such as:

  • expected sample count/rate achieved;
  • no OOM/full-GC loop;
  • CPU below your chosen operational ceiling for the required duration;
  • socket/FD/local-port headroom maintained;
  • NIC/disk not saturated/dropping;
  • JTL/log evidence complete;
  • target service telemetry does not indicate the target is the bottleneck when sizing the injector.

The exact percentages are environment policy, not JMeter universal constants. Record them before stepping load.

Knowledge check

When is adding heap justified?

Why can OS port tuning be the wrong first fix?

Why should antivirus/firewall changes be centrally managed?

When should DNS Cache Manager be used?

What distinguishes usable capacity from maximum typed threads?

Next lesson

Diagnose false generator/target bottlenecks

Lesson 4 engineers giant-heap, port, DNS, CPU, OS-tuning and legacy-rule failures and repairs them with the smallest evidence-backed change.

Official references and version notes

Version and compatibility note

Version-sensitive statements were rechecked against current primary documentation on 2026-09-05. The course baseline remains Apache JMeter 5.6.3 with a Java 17 JDK. JMeter 5.6.3 requires Java 8+; the 5.6.x changes page recommends Java 17 or later. Current JMeter launcher scripts default to a 1 GiB heap (-Xms1g -Xmx1g plus a 256 MiB metaspace cap) and G1GC with -XX:MaxGCPauseMillis=250/-XX:G1ReservePercent=20. Those defaults are a starting point, not a universal sizing rule. JMeter's HTTP sampler default is HttpClient4. Its retry count defaults to 0; its documented connection TTL defaults to 60 seconds. The HTTP Request Use KeepAlive option is effective with the Apache HttpComponents implementation and is the only plan change used in the checkpoint. JMeter's own best-practice guidance says effective thread capacity depends on hardware, plan design and how fast the target responds; CLI mode, minimal listeners, CSV and only required fields reduce generator cost. The mandatory lab never changes OS ephemeral-port ranges, file-descriptor limits, firewall/antivirus state or global DNS/JDK security settings.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.