Backend Development 9 min read

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.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Measuring Per-Request Heap Memory Usage and GC Impact in SpringBoot with JMeter

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.jar

4.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.

JVMMemory Managementperformance testingJMeterSpringBootGC
Code Ape Tech Column
Written by

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

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.