Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8356194

[Linux] Increase default MaxRAMPercentage for containerized workloads

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Unresolved
    • Icon: P3 P3
    • 25
    • hotspot
    • None
    • behavioral
    • medium
    • Hide
      The default heap size if not otherwise configured with `MaxHeapSize` (or `-Xmx`) flags increases in a containerized deployment. This might be unexpected for some systems that are expecting the old default of 25% of physical memory for heap. Such systems would need to explicitly set `MaxRAMPercentage` to the old value.
      Show
      The default heap size if not otherwise configured with `MaxHeapSize` (or `-Xmx`) flags increases in a containerized deployment. This might be unexpected for some systems that are expecting the old default of 25% of physical memory for heap. Such systems would need to explicitly set `MaxRAMPercentage` to the old value.
    • Other
    • Implementation

      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 for docker or podman). 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.

            sgehwolf Severin Gehwolf
            sgehwolf Severin Gehwolf
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: