In several journals, articles, blogs and all throughout the internet there is one common theme echoed: “Serial GC is not meant for any serious applications. It should be used only for prototype application. It’s only meant for desktop application or applications that have few hundred MBs of heap size. It shouldn’t be used in production.” To question this status quo theme, we conducted the below study on a major travel web services application in North America (Kindly apologizes, I can’t disclose their name).
We believe these sort of study would yield more meaningful results when they are conducted in real production traffic. Thus we configured 2 servers, one with G1 GC setting and other with Serial GC Setting in the production environment. We picked G1 GC as it’s the latest GC collector and default GC collector since Java 9. Remaining all other servers in production environment runs were running with its old GC setting (which is of no interest to this article). Load Balancer was equally distributing the traffic across all the servers. We let the servers run for a 24 hour period on a working day. So that servers can experience both high tide traffic volume and low tide traffic volume. This application runs on RedHat Linux 5.x, Java 7, Tomcat 7 and services SOAP requests. It uses popular frameworks such as Axis2, Spring, Apache Commons.
Below are the two GC Settings that were instituted:
- G1 GC
-Xms6144m -Xmx6144m -XX:MaxPermSize=512m -XX:PermSize=300m -XX:+UseG1GC -XX:MaxGCPauseMillis=500
- Serial GC
-Xms6144m -Xmx6144m -XX:MaxPermSize=512m -XX:PermSize=300m -XX:NewSize=4608m -XX:MaxNewSize=4608m -XX:-UseSerialGC
Following tools were used for this study:
1. CPU & memory utilization metric captured from the APM tool – New Relic
2. Throughput & Latency metric was captured from universal garbage collection analysis tool http://gceasy.io/.
Tuning Serial GC
As it is recommended that G1 GC will dynamically adjust the generational space, we didn’t specify any young/old generational size.
On the other hand in Serial GC setting, we have configured the Young Generation size to be 4 GB, which is 2/3rd of the overall heap. We intentionally declared such high young generational size, because we know for this application, significant of the objects are short-lived. As it’s Webservice application, when a SOAP request enters the application lot of objects are created, once the request is serviced and the response is sent back, all those objects dies down. There are very limited long-lived objects. Thus we intentionally tuned young generation size to be larger than old generation size.
Key Performance Indicators
Below table summarizes KPI metrics of this study:
|Avg CPU Utilization||Throughput||Latency||GC Report|
|G1 GC||25.1%||97.622%||3 secs 110 ms||G1 GC Report|
|Serial GC||23.3%||98.273%||2 secs 640 ms||Serial GC Report|
There are several interesting observations in this study:
1. CPU Spike in G1 GC
You can notice that CPU consumption was slightly higher in G1 GC settings (25.1%) than Serial GC settings (23.3%). Leaving that fact aside, we ran into an issue during server startup time. There were significant CPU spikes in G1 GC settings during server startup time. It caused load balancer to evict the G1 GC enabled server from its pool. Thus only after few minutes of server startup time when CPU utilization settled down, we could add back the G1 GC server to the load balancer.
2. Comparable Throughput:
Throughput in G1 GC is 97.62%, whereas serial GC is 98.27%. Throughput is marginally better in Serial GC.
3. Better Latency in Serial GC:
To everyone’s surprise, max GC pause time (i.e. latency) of Serial GC is better than G1 GC 🙂. Serial GC’s maximum pause time is 2 secs 640 ms, whereas G1 GC’s maximum pause time is 3 sec 110 ms. This is despite the fact that G1 GC’s max pause time is configured to 500 ms.
This study makes us question the validity of the status quo statement: “Serial GC is not for serious applications”. This study also reveals that tuning Serial GC with ‘human intelligence’ would be able to provide better or comparable results with ‘machine intelligence’ tuned G1 Garbage collector algorithm. Please share your comments/criticism/feedback on this study, looking forward to a healthy conversation.
Note: This article is in no way meant to offend G1 GC algorithm and its fans. In fact, I am a big fan of G1 GC because of it’s auto-tuning capabilities + capability to set max pause time option. These features are a boon to the development community. Of course, it’s needless to say that properly tuned G1 GC setting might be able to deliver better results than the default/out of the box G1 GC setting that’s used in this study.
June 27, 2018 at 11:46 am
Hey guys, using -XX:-UseSerialGC you write about actually disables the serial gc, to enable it you need to use -XX:+UseSerialGC . You can verify it for example using
java -XX:-UseSerialGC -XX:+PrintFlagsFinal 2>/dev/null |grep ‘Use.*GC’
August 24, 2016 at 10:50 pm
When used the option -XX:MinHeapFreeRatio=40 and -XX:MaxHeapFreeRatio=40 in G1 GC it has gave back almost all the unused memory to OS while the SerialGC just gave some hundred mbs back to OS.