Java Tuning on OpenShift
Environment
- Red hat OpenShift Container Platform (OCP)
- 4.x
- 3.x
- Red Hat build of OpenJDK:
- OpenJDK 8u191+
- OpenJDK 11
- OpenJDK 17
- OpenJDK 21
Issue
- Java Tuning on OpenShift
Resolution
Do not set initial heap size equal to max heap size. In cloud environments (OpenShift), the goal is normally to minimize memory footprint. Initial heap size must be lower than the maximum heap size for the JVM to return memory to the OS/container. Only testing and requirements can determine the appropriate tradedoff between commit/uncommit overhead and memory footprint; however, often an arbitrary low value is fine.
The following collectors are best in cloud environments due to functionality to release memory back to the OS/container and minimize memory footprint:
- Parallel
- Shenandoah
- G1 (JDK17+)
Typical JVM Options:
- JDK8 Serial (1 cpu/core):
-server -XX:+UseSerialGC -Xms256M -Xmx2560M -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -verbose:gc -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=N -XX:GCLogFileSize=N[K|M|G] -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/
- JDK8 Parallel:
-server -XX:+UseParallelGC -XX:+UseParallelOldGC -Xms256M -Xmx2560M -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -verbose:gc -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=N -XX:GCLogFileSize=N[K|M|G] -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/
- JDK 8 Shenandoah:
-server -XX:+UseShenandoahGC -XX:+AlwaysPreTouch -XX:+UseNUMA -XX:-UseBiasedLocking -XX:+UseLargePages -Xms256M -Xmx2560M -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -verbose:gc -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=N -XX:GCLogFileSize=N[K|M|G] -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/
- JDK17 Serial (1 cpu/core):
-server -XX:+UseSerialGC -XX:+UseLargePages -Xms256M -Xmx2560M -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Xlog:gc*,safepoint=info:file=gc.log:time,uptime:filecount=N,filesize=N[K|M|G] -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/
- JDK11/17 Parallel:
-server -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseLargePages -Xms256M -Xmx2560M -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Xlog:gc*,safepoint=info:file=gc.log:time,uptime:filecount=N,filesize=N[K|M|G] -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/
- JDK11/17 Shenandoah:
-server -XX:+UseShenandoahGC -XX:+AlwaysPreTouch -XX:+UseNUMA -XX:-UseBiasedLocking -XX:+UseLargePages -Xms256M -Xmx2560M -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Xlog:gc*,safepoint=info:file=gc.log:time,uptime:filecount=N,filesize=N[K|M|G] -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/
- JDK17 G1 (>2GB and >2 cores):
-server -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent -XX:MaxGCPauseMillis=500 -Xms2048M -Xmx4096M -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Xlog:gc*,safepoint=info:file=gc_%p_%t.log:time,uptime:filecount=N,filesize=N[K|M|G] -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/
Restricting Footprint
Also, it is possible to restrict the whole JVM size, i.e. footprint, not just the Heap size.
MaxRAM: Sets the total amount of memory used by the JVM maximum to N (where n may be expressed in terms of megabytes 100m or gigabytes 2G). Not just the Heap size.
One can consider using the percentage flags Min|MaxRAMPercentage, and InitialRAMPercentage, which give more flexibility with a precise percentage of the heap usage:
InitialRAMPercentage=N: Set initial heap size as a percentage of total memoryMaxRAMPercentage=N: Set maximum heap size as a percentage of total memoryMinRAMPercentage=N: Set minimum heap size as a percentage of total memory
Although being deprecated1, the fraction forms can still be used:
InitialRAMFraction: Set the initial heap as a fraction of the the RAM.- Using
Min|MaxRAMFractionsets the JVM to use availablememory/MaxRAMFraction as max heap, and has default as 4, so the Heap occupies 25% of the memory1:
The relation between the above flags above is given by:
MaxHeapSize = MaxRAM * 1 / MaxRAMFraction
These flags are described on the solution Usage of OpenJDK 11 flags InitialRAMPercentage and MaxRAMPercentage and require -XX:+UseContainerSupport flag, which is enabled by default. And If you set a value for Xms/Xmx, these options are ignored.
Other flags
One should not to use UseCGroupMemoryLimitForHeap on JDK 1.8.191 or later. This flag tells the JVM to use the information in /sys/fs/cgroup/memory/memory.limit_in_bytes to calculate memory defaults.
Fraction forms are being deprecated: Content from www.oracle.com is not included.Java 1.8.191 - Release Notes and Content from bugs.openjdk.java.net is not included.JDK-8187125 and likely will be removed.
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.