Default JVM GC collector on runtime container

Solution Verified - Updated

Environment

  • OpenJDK 8, 11, 17
  • Red hat OpenShift Container Platform (OCP)
    • 3.x/4.x
    • Docker/CRI-O

Issue

  • What is the default GC collector on Docker container?
  • Given that ParallelGC is the default collector for JDK 8 and G1GC is the default for JDK 11, why the container is running with Serial Gc?

Resolution

The JVM will set different default GCs based on the container memory and CPUs available, setting one CPU as limit/request of the deployment (and therefore on the pod), will make the JVM use SerialGC as collector. It will not overwrite the user but it will use a different default GC 1.
This overwrites the default GC (see table below), where when using JDK 8 user would expect ParallelGC, and JDK 11 we would expect G1GC, but the JVM will change the default GC for Serial in case the number of cpus (spec.container request|limit mostly since JVM is a nonelastic process) is 1.
Also for OpenJDK 17, the memory plays a role on the default selected collector where 1Gi memory(or less) containers tend to select SerialGC instead of G1GC.

Examples

  • For instance, if the user has a JDK 8 image, set CPU == 1, so then the serial GC will be used, even though the default GC is G1GC collector.
  • For instance, if the user has a JDK 11 image, set CPU == 1, so then the serial GC will be used, even though the default GC is G1GC collector.
1

Default means the user is not setting the collector and the JDK is using the default. The JVM will not overwrite the user choices, i.e. setting a custom GC collector won't be overwritten.

Root Cause

As explained on the solution Should -XX:+UseContainerSupport flag be used in OpenJDK images?, after OpenJDK 1.8.131+ the JVM is container aware and therefore it use the container cpus (via cgroups) to calculate threads such as Concurrent and Parallel threads, but also memory limits.

JDK versionDefault Gc Collector
JDK 8ParallelGC
JDK 11G1GC
JDK 17G1GC

Diagnostic Steps

Get the limit/request cpu resources on the pod/deployment

$ oc get pod $podname -o json | grep cpu
                        "cpu": "1", <--- limit is the first number
                        "cpu": "1", <---- request is the second number

$ oc get $podname -o json gives below:

                "resources": {
                    "limits": {
                        "cpu": "1",
                        "memory": "2Gi"
                    },
                    "requests": {
                        "cpu": "1",
                        "memory": "1Gi"
Category

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.