1. Overview
1.概述
Heap size is an essential parameter of Java applications. It directly affects how much memory we can use and indirectly impacts the applications’ performance. For example, the usage of compressed pointers, the number and duration of garbage collection cycles, etc.
堆大小是 Java 应用程序的一个重要参数。它直接影响我们可以使用多少内存,并间接影响应用程序的性能。例如,压缩指针的使用、垃圾回收周期的数量和持续时间等。
In this tutorial, we’ll learn how to use the –XX:MaxRAM flag to provide more tuning opportunities for the heap size calculation. This is especially important while running an application inside a container or on different hosts.
在本教程中,我们将学习如何使用 –XX:MaxRAM 标记为堆大小计算提供更多调整机会。这对于在容器内或不同主机上运行应用程序尤为重要。
2. Heap Size Calculations
2.堆规模计算
Flags for configuring a heap can work together and, also, can override each other. Understanding their relationships is important to get more insights into their purpose.
用于配置堆的标志可以协同工作,也可以相互覆盖。了解它们之间的关系对于深入了解它们的用途非常重要。
2.1. Using -Xmx
2.1.使用 -Xmx
The primary ways to control the heap size are -Xmx and -Xms flags, which control the maximum and initial size, respectively. It’s a powerful tool but doesn’t consider available space on a machine or container. Let’s say we’re running an application on various hosts where the available RAM spans from 4 GB to 64 GB.
控制堆大小的主要方法是-Xmx和-Xms标志,它们分别控制最大和初始大小。它是一个功能强大的工具,但不考虑机器或容器上的可用空间。假设我们在不同主机上运行一个应用程序,其可用内存从 4 GB 到 64 GB 不等。
Without -Xmx, JVM automatically allocates around 25% of available RAM for the application heap. However, in general, the initial heap size allocated by JVM depends on various parameters: system architecture, version of JVM, platform, etc.
在没有 -Xmx 的情况下, JVM 会自动为应用程序堆分配约 25% 的可用 RAM。不过,一般来说,JVM 分配的初始堆大小取决于各种参数:系统架构、JVM 版本、平台等。
This behavior might be undesirable in some cases. Depending on the available RAM, it might allocate dramatically different heaps. Let’s check how much JVM allocates by default on the machine with 24 GB of RAM:
在某些情况下,这种行为可能并不可取。根据可用内存的不同,它分配的堆可能大相径庭。让我们检查一下 JVM 在内存为 24 GB 的机器上默认分配了多少资源:
$ java -XX:+PrintFlagsFinal -version |\
grep -e '\bMaxHeapSize\|\bMinHeapSize\|\bInitialHeapSize'
size_t InitialHeapSize = 402653184 {product} {ergonomic}
size_t MaxHeapSize = 6442450944 {product} {ergonomic}
size_t MinHeapSize = 8388608 {product} {ergonomic}
JVM allocated roughly 6 GB or 25%, which might be too much for our application. Setting the max heap to a specific value might also create issues. If we’re using -Xmx4g, it might fail for hosts with less than available memory, and also, we won’t get additional memory we can have:
JVM 分配了大约 6 GB 或 25%的内存,这对于我们的应用程序来说可能太多了。如果我们使用的是 -Xmx4g,它可能会导致可用内存不足的主机无法运行,而且我们也无法获得额外的可用内存:
$ java -XX:+PrintFlagsFinal -Xmx4g -version |\
grep -e '\bMaxHeapSize\|\bMinHeapSize\|\bInitialHeapSize'
size_t InitialHeapSize = 402653184 {product} {ergonomic}
size_t MaxHeapSize = 4294967296 {product} {command line}
size_t MinHeapSize = 8388608 {product} {ergonomic}
In some cases, this problem can be solved by calculating -Xmx on the fly with scripts. However, it bypasses the JVM heuristic that might be more precise about the application needs.
在某些情况下,可以通过使用脚本即时计算-Xmx来解决这个问题。但是,这样做会绕过 JVM 启发式,而 JVM 启发式可能会更精确地了解应用程序的需求。
2.2. Using -XX:MaxRAM
2.2.使用 -XX:MaxRAM
The flag -XX:MaxRAM aims to resolve the problem described above. First, it prevents JVM from over-allocating memory on the systems with lots of RAM. We can think about this flag as “run the app, but pretend that you have at most X amount of RAM.”
标记-XX:MaxRAM旨在解决上述问题。首先,它可以防止 JVM 在拥有大量内存的系统上过度分配内存。我们可以将此标记理解为 “运行应用程序,但假装您最多拥有 X 内存”。
Additionally, -XX:MaxRAM allows JVM to use a standard heuristic for the heap size. Let’s review the previous example, but using -XX:MaxRAM:
此外,-XX:MaxRAM 允许 JVM 使用标准启发式来确定堆大小。让我们回顾一下前面的示例,但使用的是 -XX:MaxRAM:
$ java -XX:+PrintFlagsFinal -XX:MaxRAM=6g -version |\
grep -e '\bMaxHeapSize\|\bMinHeapSize\|\bInitialHeapSize'
size_t InitialHeapSize = 100663296 {product} {ergonomic}
size_t MaxHeapSize = 1610612736 {product} {ergonomic}
size_t MinHeapSize = 8388608 {product} {ergonomic}
JVM calculates the maximum heap size in this case but assumes we have only 6 GB of RAM. Note that we should not use -Xmx with -XX:MaxRAM. Because -Xmx is more specific, it would override -XX:MaxRAM:
在这种情况下,JVM 会计算最大堆大小,但假设我们只有 6 GB 内存。请注意,我们不应将 -Xmx 与 -XX:MaxRAM 一起使用。因为 -Xmx 更为具体,它将覆盖 -XX:MaxRAM :
$ java -XX:+PrintFlagsFinal -XX:MaxRAM=6g -Xmx6g -version |\
grep -e '\bMaxHeapSize\|\bMinHeapSize\|\bInitialHeapSize'
size_t InitialHeapSize = 100663296 {product} {ergonomic}
size_t MaxHeapSize = 6442450944 {product} {command line}
size_t MinHeapSize = 8388608 {product} {ergonomic}
This flag can improve resource utilization and heap allocation. However, we still don’t have control over how much of the RAM should be allocated to the heap.
该标记可提高资源利用率和堆分配。但是,我们仍然无法控制应将多少 RAM 分配给堆。
2.3. Using -XX:MaxRAMPercentage and -XX:MinRAMPercentage
2.3.使用 -XX:MaxRAMPercentage 和 -XX:MinRAMPercentage
Now we’re in control and can tell JVM how much RAM it should consider. Let’s define our strategies for allocating the heap. The -XX:MaxRAM flag works well with -XX:MaxRAMPercentage and -XX:MinRAMPercentage. They provide even more flexibility, especially in containerized environments. Let’s try to use it with -XX:MaxRAM and set the heap as 50% of available RAM:
现在我们可以控制并告诉 JVM 它应该考虑多少 RAM。让我们定义分配堆的策略。-XX:MaxRAM 标记与 -XX:MaxRAMPercentage 和 -XX:MinRAMPercentage 配合使用。它们提供了更大的灵活性,尤其是在容器化环境中。让我们尝试将其与 -XX:MaxRAM 配合使用,并将堆设置为可用 RAM 的 50%:
$ java -XX:+PrintFlagsFinal -XX:MaxRAM=6g -XX:MaxRAMPercentage=50 -version |\
grep -e '\bMaxHeapSize\|\bMinHeapSize\|\bInitialHeapSize'
size_t InitialHeapSize = 100663296 {product} {ergonomic}
size_t MaxHeapSize = 3221225472 {product} {ergonomic}
size_t MinHeapSize = 8388608 {product} {ergonomic}
There’s a common confusion about the -XX:MinRAMPercentage. It doesn’t behave as -Xms. Although, it would be reasonable to assume that it sets the minimum heap size. Let’s check the following setup:
关于 -XX:MinRAMPercentage,有一个常见的混淆。它的行为与 -Xms不同。尽管我们有理由认为它设置了最小堆大小。让我们检查以下设置:
$ java -XX:+PrintFlagsFinal -XX:MaxRAM=16g -XX:MaxRAMPercentage=10 -XX:MinRAMPercentage=50 -version |\
grep -e '\bMaxHeapSize\|\bMinHeapSize\|\bInitialHeapSize'
size_t InitialHeapSize = 268435456 {product} {ergonomic}
size_t MaxHeapSize = 1719664640 {product} {ergonomic}
size_t MinHeapSize = 8388608 {product} {ergonomic}
We set both -XX:MaxRAMPercentage and -XX:MinRAMPercentage, but it’s clear that only -XX:MaxRAMPercentage is working. We allocated 10% of 16 GB RAM to the heap. However, if we reduce the available RAM to 200 MB, we’ll get a different behavior:
我们同时设置了 -XX:MaxRAMPercentage 和 -XX:MinRAMPercentage,但显然只有 -XX:MaxRAMPercentage 起作用。我们为堆分配了 16 GB RAM 的 10%。但是,如果我们将可用 RAM 减少到 200 MB,就会出现不同的行为:
$ java -XX:+PrintFlagsFinal -XX:MaxRAM=200m -XX:MaxRAMPercentage=10 -XX:MinRAMPercentage=50 -version |\
grep -e '\bMaxHeapSize\|\bMinHeapSize\|\bInitialHeapSize'
size_t InitialHeapSize = 8388608 {product} {ergonomic}
size_t MaxHeapSize = 109051904 {product} {ergonomic}
size_t MinHeapSize = 8388608 {product} {ergonomic}
In this case, the heap size is controlled by -XX:MinRAMPercentage. This flag kicks in when the available RAM drops to less than 200 MB. Now, we can bump the heap to 75%:
在这种情况下,堆大小由 -XX:MinRAMPercentage 控制。当可用 RAM 降至 200 MB 以下时,该标记会启动。现在,我们可以将堆提高到 75%:
$ java -XX:+PrintFlagsFinal -XX:MaxRAM=200m -XX:MaxRAMPercentage=10 -XX:MinRAMPercentage=75 -version |\
grep -e '\bMaxHeapSize\|\bMinHeapSize\|\bInitialHeapSize'
size_t InitialHeapSize = 8388608 {product} {ergonomic}
size_t MaxHeapSize = 134217728 {product} {ergonomic}
size_t MinHeapSize = 8388608 {product} {ergonomic}
If we proceeded to apply -XX:MaxRAMPercentage for such tiny heaps, we would get 20 MB of heap, which might not be enough for our purposes. That’s why we have different flags for small and large heaps. The -XX:MaxRAM flag works nicely with both of them and gives us more control.
如果我们继续为如此小的堆应用 -XX:MaxRAMPercentage,我们将获得 20 MB 的堆,这可能无法满足我们的目的。这就是为什么我们为小堆和大堆设置了不同的标记。-XX:MaxRAM标记与它们都能很好地配合,并为我们提供了更多控制。
3. Conclusion
3.结论
Controlling heap size is crucial for Java applications. Allocating more memory isn’t necessarily good; at the same time, allocating not enough memory is bad.
控制堆大小对 Java 应用程序至关重要。分配更多的内存并不一定是好事,同时,分配不足的内存也是坏事。
Using -Xmx, -XX:MaxRAM, -XX:MaxRAMPercentage, and -XX:MinRAMPercentage can help us tune our application better and improve performance.
使用-Xmx、-XX:MaxRAM、-XX:MaxRAMPercentage和-XX:MinRAMPercentage可以帮助我们更好地调整应用程序并提高性能。