Summary
Increase the default MaxRAMPercentage
value on Linux for containerized systems from 25% to 75%. This allows for better memory utilization when deployed on container orchestration systems such as Kubernetes with container memory limits already in place.
Problem
Deployments of the JVM in containers are common today. Many of those systems run on Kubernetes (K8S) and tune the memory needs on a per-pod or per-container basis. In such a scenario, the automatic container memory limit detection mechanism of the JVM kicks in. It derives the heap size from the detected physical memory. In the case of K8S, this would be the container limit. Most containerized deployments run a single application in that container and expect the container to use the memory efficiently within its bounds. The JVM default setting of 25% for MaxRAMPercentage
prevents that.
The default JVM setting of MaxRAMPercentage
of 25% made sense at a time when such deployment scenarios were less prevalent than today. Shared, multi-user deployments were the norm, and for them it made sense to only use a quarter of physical memory for the JVMs heap size. After all, other users might run other JVM processes on the same system that would compete for memory.
This has changed. In modern cloud environments, applications are tuned by container and expect applications running in such resource-constrained environments to best utilize the given resources. Affording the JVM only 25% of the container memory for its heap runs contrary to this goal. Most of the memory should be available for the heap and only a smaller portion for off-heap memory.
Solution
Increase the MaxRAMPercentage
value for containerized systems from 25% to 75% to increase the chance of better memory utilization when deployed in a container. Do this only when OSContainer::is_containerized()
reports true
, indicating a containerized Linux system.
Specification
diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp
index 9bd45b0fec8..aa6e28b0ac1 100644
--- a/src/hotspot/os/linux/os_linux.cpp
+++ b/src/hotspot/os/linux/os_linux.cpp
@@ -4432,6 +4432,13 @@ void os::pd_init_container_support() {
OSContainer::init();
}
+// Called before ergonomic flags processing
+void os::initialize_max_ram_percentage() {
+ if (OSContainer::is_containerized()) {
+ FLAG_SET_ERGO_IF_DEFAULT(MaxRAMPercentage, 75.0);
+ }
+}
+
void os::Linux::numa_init() {
// Java can be invoked as
diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp
index ee1f0a3b081..58f1e740f97 100644
--- a/src/hotspot/share/runtime/os.cpp
+++ b/src/hotspot/share/runtime/os.cpp
@@ -484,6 +484,7 @@ void os::init_before_ergo() {
// VM version initialization identifies some characteristics of the
// platform that are used during ergonomic decisions.
VM_Version::init_before_ergo();
+ LINUX_ONLY(initialize_max_ram_percentage();)
}
void os::initialize_jdk_signal_support(TRAPS) {
diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp
index dde80806912..e6f5ec77cfd 100644
--- a/src/hotspot/share/runtime/os.hpp
+++ b/src/hotspot/share/runtime/os.hpp
@@ -256,6 +256,7 @@ class os: AllStatic {
static void initialize_initial_active_processor_count();
LINUX_ONLY(static void pd_init_container_support();)
+ LINUX_ONLY(static void initialize_max_ram_percentage();)
static void init(void); // Called before command line parsing
Compatibility Risks
Kubernetes:
- Kubernetes has configuration options for "Memory requests" and "Memory limit". If "Memory limit" is not set, Kubernetes runs the container with no (upper) memory limit. Before this CSR, the JVM may only use up to 25% of the node's total memory for the Java heap. After this CSR, the JVM may use up to 75% of the node's memory for the Java heap as given by the OS (subject to competition with other active processes on the same node). In some cases, this may cause overconsumption of memory resources. To fix such problems, the user should explicitly set the "Memory request"/"Memory limit" of their Kubernetes deployments instead of relying on the previous JVM behavior.
Other Linux-based container orchestration environments
- In general, after this CSR, out of the box, a JVM process will be able to use more memory resources for the Java heap than it used to previously. If the user wants to limit the Java heap of the JVM process within a container, they should use the appropriate mechanisms of the container orchestration environments to set the desired limits. For example, use a memory limit for the container (
--memory=<n>
and--memory-swap=<n>
switches fordocker
orpodman
). Another option is to disable the default container detection mechanism heuristics by explicitly specifying-XX:MaxRAMPercentage=<n>
.
As a stop-gap measure, if the user cannot immediately modify their configuration settings per the above suggestions, they can use the flag -XX:MaxRAMPercentage=25.0
to revert to the old behavior.
- csr of
-
JDK-8350596 [Linux] Increase default MaxRAMPercentage for containerized workloads
-
- In Progress
-