基于容器的Java内存参数解析

2023-01-07 1780阅读

温馨提示:这篇文章已超过481天没有更新,请注意相关的内容是否还可用!

基于容器的Java内存参数解析

基于容器的Java内存参数解析
(图片来源网络,侵删)
基于容器的Java内存参数解析
(图片来源网络,侵删)

在物理服务器上运行Java应用程序时(这里主要区别于容器平台,所以在此说明)服务器内存介绍参数,我们通常使用Java虚拟机参数“-Xms,-Xmx”来指定Java堆内存的初始值和最大值价值。 如果我们想把我们的应用移植到容器平台上,那么在容器环境下如何配置Java堆内存大小呢? 有什么最佳实践吗? 在本文中,我们将讨论可用于指定 Java 堆内存大小的 JVM 参数和最佳选择。

在我们的容器环境中,通常可以借助以下三个不同的选项来指定容器中 Java 堆内存的大小。 具体的:

1. -XX:最小(最大)RAMFraction

2. -XX:最小(最大)RAM 百分比

3.-Xms,-Xmx

下面简单分析一下这几个JVM参数:

1. -XX:最小(最大)RAMFraction

参数“-XX:MinRAMFraction”和“-XX:MaxRAMFraction”支持的JDK版本:目前只支持Java 8 update 131到Java 8 update 190的版本。因此,如果你使用的是不同版本的JDK,你不能使用此选项。

原理分析:

假设我们已经为容器分配了1GB的内存,那么如果我们配置-XX:MaxRAMFraction=2,将会为Java堆大小分配大约512GB(即1GB的1/2)。

如果要使用“-XX:MaxRAMFraction”JVM 参数,请确保将这两个附加 JVM 参数与“-XX:+UnlockExperimentalVMOptions 和 -XX:+UseCGroupMemoryLimitForHeap”一起传递。 只有我们配置了这两个JVM参数,JVM才会从容器的内存大小中推导出堆内存大小值服务器内存介绍参数,否则,它会从底层主机的内存大小中推导出堆内存大小值。

[administrator@JavaLangOutOfMemory ~ ]% docker run -m 1GB openjdk:8u131 java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction = 2 
-XshowSettings:vm-版本VM设置:最高堆大小(估计):494.94M

通过上面的命令,我们可以看到此时docker容器的内存设置为“1GB”(即-m 1GB)和“-XX:MaxRAMFraction = 2”。 基于此设置,JVM 分配的最大堆大小为 494.9MB(大约是 1GB 大小的一半)。

注意:“-XX:MaxRAMFraction”和“-XX:MinRAMFraction”都用于确定最大 Java 堆大小。 JDK 开发团队可以使用比“-XX:MinRAMFraction”更好的名称。 这个名字让我们认为“-XX:MinRAMFraction”参数是用来配置最小堆大小的。 但是这是错误的。 要详细了解它们之间的差异,请继续阅读本文。

会有什么限制? 以下是这种方法的缺点:

1.假设我们配置docker内存大小的40%,我们必须设置“-XX:MaxRAMFraction=2.5”。 当传递 2.5 作为值时,JVM 将不会启动。 这是因为“-XX:MaxRAMFraction”只能接受整数值,不能接受小数值。 请参阅以下 JVM 无法启动的示例。

[administrator@JavaLangOutOfMemory ~ ]% docker run -m 1GB openjdk:8u131 java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=2.5 -XshowSettings:vm -version VM
Improperly specified VM option 'MaxRAMFraction=2.5'
Improperly specified VM option 'MaxRAMFraction=2.5'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

2. 在此选项中,Java 应用程序的堆大小将派生自容器的内存大小(因为它是分数基础)。 假设如果我们的应用程序需要 1GB 的堆大小以获得最佳性能,并且如果容器配置为以小于 1GB 的内存大小运行,我们的应用程序仍将运行,但性能特征较差。

3.现代Java版本不推荐使用该参数。 仅支持 Java 8 update 131 到 Java 8 update 190。

2. -XX:最小(最大)RAM 百分比

此参数“-XX:MaxRAMPercentage”、“-XX:MinRAMPercentage”支持JDK版本:Java 8 update 191及更高版本。 因此,如果在较早的 JDK 版本上运行,则不能使用此 JVM 参数。

原理分析:

假设我们已经为容器分配了 1 GB 的内存,那么如果我们配置 -XX:MaxRAMPercentage=50,我们将为应用程序的 Java 堆大小分配大约 512GB(1GB 的 1/2)。

[administrator@JavaLangOutOfMemory ~ ]% docker run -m 1GB openjdk:10 java -XX:MaxRAMPercentage = 50 -XshowSettings:vm -version

在这里,我们可以看到Docker容器的内存现在设置为-m 1GB和-XX:MaxRAMPercentage = 50。根据这个参数配置,JVM分配的最大堆大小为494.9MB(大约是1GB的一半)。

备注:网上一篇文章提到传递“-XX:MaxRAMPercentage”、“-XX:InitialRAMPercentage”、“-XX:MinRAMPercentage”时,需要传递JVM参数-XX。 不是这样。 JVM中的默认参数传递了“-XX:+UseContainerSupport”。 因此,我们不需要明确定义。

会有什么限制? 以下是这种方法的缺点:

1、Java早期版本不支持该参数。 它仅在 Java 8 update 191 中受支持。

2. 在此选项中,我们的 Java 应用程序的堆大小将派生自容器的内存大小(因为它是基于百分比的)。 假设我们的应用程序需要 1GB 的堆大小以获得最佳性能,如果您将容器配置为以小于 1GB 的内存大小运行,您的应用程序仍然可以运行,但性能会很差。

3.-Xmx

该参数支持所有 JDK 版本。

原理分析:

使用这种类型的“-Xmx”JVM参数,我们可以指定一个细粒度的具体大小,比如512MB、1024MB。

非容器(传统物理服务器世界)环境支持的-Xmx操作如下:

[administrator@JavaLangOutOfMemory ~ ]%java -Xmx512m -XshowSettings:vm -version

容器环境支持的-Xmx操作如下:

[administrator@JavaLangOutOfMemory ~ ]%docker run -m 1GB openjdk:8u131 java -Xmx512m -XshowSettings:vm -version VM

备注:如果分配的“-Xmx”大于容器的内存大小,我们的应用会遇到“java.lang.OutOfMemoryError: kill process or sacrific child process”等异常事件。

无论我们使用什么选项来配置堆大小(即 -XX:MaxRAMFraction、-XX:MaxRAMPercentage、-Xmx),始终确保为我们的容器(即 -m)分配至少比堆大小多 25% 的内存价值。 假设我们已经配置-Xmx值为2GB,那么配置容器的内存大小至少为2.5GB。 即使我们的 Java 应用程序是将在容器上运行的唯一进程,也要这样做。 因为很多工程师认为一个Java应用程序不会消耗超过-Xmx这个值。 那是不对的。 除了堆空间之外,应用程序还需要用于 Java 线程、垃圾收集、元空间、本机内存和套接字缓冲区的空间。 所有这些组件都需要超出分配的堆大小的额外内存。 除此之外,APM 代理、splunk 脚本等其他小进程也需要内存。

如果仅在容器中运行 Java 应用程序,请将初始堆大小设置为与最大堆相同的大小值(即,使用“-XX:InitialRAMFraction”、“-XX:InitialRAMPercentage”、“-Xms”)。 将初始堆大小和最大堆值设置为相同具有一定的优势。 其中之一是:会减少垃圾回收的停顿时间。 因为只要堆大小从最初分配的大小增加,它就会暂停 JVM。 当初始堆大小和最大堆大小设置为相同时,可以避免这种情况。 除此之外,如果我们没有分配容器的内存大小,那么 JVM 甚至不会启动(这比在执行事务时遇到 OutOfMemoryError 更好)。

在我看来,我倾向于使用 -Xmx 选项而不是 -XX:MaxRAMFraction、-XX:MaxRAMPercentage 选项来指定容器世界中的 Java 堆大小,原因如下: 内存大小是决定应用程序性能的关键。 它会影响垃圾收集行为和性能特征,这些行为和性能特征预计不会由容器的内存设置决定。

使用“-Xmx”,我可以设置细粒度/精度值,如 512MB、256MB 等。另外,所有 Java 版本都支持 -Xmx。

- EOF -

如果您喜欢本文,请点赞、收藏、留言,或点击右下角将文章分享给您的朋友~~~

基于容器的Java内存参数解析

基于容器的Java内存参数解析

卢加李

“路在我脚下~”

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]