How Much Heap Does a Single SpringBoot HTTP Request Consume? A Full GC‑Based Experiment
This article presents a step‑by‑step experiment that uses JMeter to generate 20,000 HTTP calls against a SpringBoot 2.5.4 service, captures detailed GC logs, calculates the heap memory allocated per request, analyses the impact of request payload and logging, and offers practical tuning recommendations.
Background
In production environments it is often necessary to perform full‑stack load testing, tune GC parameters, and optimise JVM memory allocation. Knowing the exact heap size required for a single RPC or HTTP request enables precise calculation of total heap needs for a given concurrency level and helps predict GC frequency.
Experiment Design
The goal is to measure how much heap memory a single HTTP request consumes in a SpringBoot application.
Create a new SpringBoot 2.5.4 project.
Add a POST /create endpoint that accepts an Order object.
Add a GET /gc endpoint that triggers System.gc().
Configure JMeter to run a test plan with 10 threads, each performing 2,000 calls to the /create endpoint (total 20,000 calls).
Enable detailed GC logging in the JVM (see command line flags below) and record the memory usage of the young generation before and after the test.
Key Commands and Configuration
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.jarSpringBoot Controller Sample
@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("收到提单请求 cnt{}:{}", count.getAndIncrement(), order);
return "ok";
}
@ResponseBody
@RequestMapping(value = "gc", method = RequestMethod.GET)
public String gc() {
System.gc();
return "ok";
}
}JMeter Test Plan
A thread group with 10 threads, each looping 2,000 times, is created. The HTTP Request defaults are set to Content-Type: application/json and the request body contains a JSON payload (initially 50 characters).
Experiment Procedure
Start the SpringBoot application with the JVM options above (heap 4 GB, young generation 2 GB, SurvivorRatio = 8).
Manually invoke curl http://localhost:8080/gc a few times before the load test to clear existing objects.
Run the JMeter test plan, which performs 20,000 HTTP calls.
After the test, trigger a manual GC and examine the GC log to determine how much young‑generation memory was allocated during the test.
Results
Even though the request body is only ~50 bytes, each HTTP call caused the JVM to allocate roughly 34 KB of heap memory. Adding a larger detail field (≈1,200 characters) increased the allocation to about 36 KB , confirming that payload size contributes linearly.
When detailed request logging is enabled (the log.warn(...) line uncommented), the per‑request memory usage rose to 56 KB**, a 20 KB increase caused by the additional log objects.
Removing the detail field reduced the allocation to 35.7 KB , showing that log size has a noticeable impact on memory consumption.
Conclusions and Recommendations
In a simple SpringBoot service, a single HTTP request consumes about 34 KB of heap memory; this is a lower bound for more complex services.
Large request payloads and extensive logging increase heap usage and can trigger more frequent GC cycles, degrading performance.
Control the size of individual log entries and avoid logging large request bodies in high‑throughput paths.
When planning capacity, consider that a 0.5 MB per‑request cost (as observed in some RPC services) at 500 RPS would require ~15 GB of memory per minute, necessitating multiple young‑generation GCs.
Practical Tips
Use lightweight request objects and avoid unnecessary copying.
Log only essential information; consider sampling or asynchronous logging for high‑volume endpoints.
Monitor GC logs regularly to detect abnormal memory allocation patterns.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.
