Measuring Per-Request Heap Memory Usage and GC Impact in SpringBoot with JMeter
This article demonstrates how to experimentally determine the heap memory allocated by individual HTTP and RPC requests in a SpringBoot application using JMeter load testing, GC logging, and code analysis, providing insights into memory consumption, GC frequency, and optimization strategies for backend performance.
In practical work, full‑link pressure testing, GC parameter tuning, and JVM memory allocation optimization are often required.
By knowing the heap memory required for a single RPC or HTTP request, you can precisely calculate the total heap needed for a given concurrency, estimate GC frequency, and target optimizations.
1. Experiment Idea
Key Actions
Create a new SpringBoot application (version 2.5.4 ).
Add a POST endpoint for JMeter to call.
Configure a JMeter test plan: each thread performs 2000 HTTP calls, 10 threads total 20000 calls.
Enable detailed GC logging in SpringBoot to record new‑generation memory allocation.
After 20000 HTTP calls, trigger a manual GC and calculate the new‑generation heap growth from the GC logs.
2. SpringBoot HTTP Interface Declaration
The following code defines a POST endpoint create and a GET endpoint for triggering GC.
@Slf4j
@RestController
public class TestController {
private AtomicLong count = new AtomicLong(0);
@ResponseBody
@RequestMapping(value = "create", method = RequestMethod.POST)
public String create(@RequestBody Order order) {
//log.warn("Received order cnt{}:{}", count.getAndIncrement(), order);
return "ok";
}
@ResponseBody
@RequestMapping(value = "gc", method = RequestMethod.GET)
public String gc() {
System.gc();
return "ok";
}
}3. JMeter Test Plan
3.1 Add Thread Group
Create a thread group with 10 threads, each looping 2000 times.
3.2 Add HTTP Defaults
Configure default server settings.
3.3 Add Request Header
Set Content-Type: application/json because the request body is JSON.
3.4 Add HTTP Request
Specify URL and request body.
4. Experiment Process
4.1 Start SpringBoot Application
Heap size 4G, young generation 2G, SurvivorRatio=8 .
Set GC log location: -Xloggc:/Users/testUser/log/gc.log
java -server
-Xmx4g -Xms4g -XX:SurvivorRatio=8 -Xmn2g
-XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=1g -XX:MaxDirectMemorySize=1g
-XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCCause -XX:+PrintGCDetails
-XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution
-XX:+UnlockDiagnosticVMOptions -XX:ParGCCardsPerStrideChunk=32768
-XX:+PrintCommandLineFlags -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-XX:ParallelCMSThreads=6 -XX:+CMSClassUnloadingEnabled
-XX:+UseCMSCompactAtFullCollection -XX:+CMSParallelInitialMarkEnabled
-XX:+CMSParallelRemarkEnabled -XX:+CMSScavengeBeforeRemark -XX:+PrintHeapAtGC
-XX:CMSFullGCsBeforeCompaction=1 -XX:CMSInitiatingOccupancyFraction=70
-XX:+UseCMSInitiatingOccupancyOnly -XX:+PrintReferenceGC
-XX:+ParallelRefProcEnabled -XX:ReservedCodeCacheSize=256M
-Xloggc:/Users/testUser/log/gc.log
-jar target/activiti-0.0.1-SNAPSHOT.jar4.2 Multiple Manual GC
Run curl http://localhost:8080/gc before the load test to clear existing objects.
4.3 JMeter Load Test
Execute the JMeter plan, invoking the HTTP endpoint 20000 times.
4.4 GC Log Interpretation
After GC, the Eden space usage returns to 0, indicating that the pre‑GC Eden size equals the total memory allocated by the 20000 HTTP calls.
5. Experiment Results
Even with a tiny request body, each HTTP call on SpringBoot allocates about 34 KB of heap memory.
Increasing the detail field to 1200 characters raises the per‑call allocation to ~36 KB, confirming that object creation overhead dominates.
5.1 Add Log Printing
log.warn("Received order cnt{}:{}", count.getAndIncrement(), order);Enabling this log increases average memory per request to ~56 KB, showing that larger logs significantly raise memory usage and may trigger more frequent GC.
Therefore, keep individual log messages small to maintain memory efficiency.
6. Real‑World Data
In production, a single RPC request can consume 0.5 MB–1 MB due to complex business logic, multiple downstream calls, SQL, cache, and logging, far exceeding the minimal 34 KB observed in the simple test.
Rough calculation: at 0.5 MB per request and 500 requests per second, the system allocates ~15 GB per minute, requiring multiple young GCs.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.