JVM GC Tuning Case Study: Reducing YGC Frequency and Boosting Service Performance
The author describes a high‑QPS Java web service, analyzes its GC behavior using jstat and gceasy, applies JVM parameter adjustments such as enlarging the young generation, tweaking MaxTenuringThreshold and disabling biased locking, and achieves roughly a 15% overall performance gain with improved GC throughput.
Hello everyone, I am Chen, and I recently performed a performance optimization on a high‑QPS web service by tuning JVM parameters, resulting in about a 15% overall performance improvement.
Project Overview: The service maintains over 1.5K QPS per machine, runs on an old machine with an 8 GB heap (4 GB young generation) using the ParNew + CMS garbage collector.
Current GC Situation: Using jstat and GC logs, the average GC pause is around 60 ms, but Young GC (YGC) occurs very frequently—about once per second, sometimes twice per second—causing noticeable response latency.
GC logs are enabled with the following JVM options:
-XX:+PrintGCDateStamps : prints timestamps for GC events.
-XX:+PrintTenuringDistribution : prints generation information.
-XX:+PrintGCApplicationStoppedTime : prints GC pause time.
-XX:+PrintGCApplicationConcurrentTime : prints time between GC pauses.
-XX:+PrintGCDetails : prints detailed GC information.
-Xloggc:../gclogs/gc.log.date : specifies GC log file path.
Analyzing the logs with gceasy shows a GC throughput of 95% (5 % of runtime spent in GC) and confirms that most pauses are YGC.
Analysis and Adjustments:
Frequent YGC
To reduce YGC frequency, the young generation size was doubled from 4 GB to 8 GB, increasing the total heap to 12 GB. This halved the YGC frequency and raised GC throughput to 97.75%.
Generation Tuning
The MaxTenuringThreshold was lowered to 4, promoting objects that survive more than four generations directly to the old generation, reducing copy overhead between survivor spaces.
Biased Lock Pause
Observed ~18 ms pauses were linked to biased lock revocation. Adding -XX:-UseBiasedLocking disables biased locking and eliminates these pauses.
Results: After the JVM parameter changes, load testing showed a noticeable performance boost without severe GC issues. YGC frequency dropped by half, GC throughput improved to 97.75%, average GC pause increased slightly to 66 ms, and CMS pause times grew as expected. Business‑impact metrics also showed a significant reduction in timeout requests caused by GC.
Key Takeaways: The author plans to create a series covering JVM fundamentals, specific performance optimization points, tuning tools, and real‑world case studies.
Conclusion: The GC tuning was successful, deepening the author's understanding of JVM GC mechanisms, though further study on the old generation and CMS is needed. Continuous monitoring and timely adjustments remain essential for performance optimization.
Promotion: The author invites readers to follow the "Code Monkey Technical Column" public account to obtain PDF collections of Spring Cloud, Spring Boot, and MyBatis advanced tutorials.
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.