最佳实践:容器的 Java 内存参数

在物理服务器中运行 Java 应用程序时,将使用 ‘-Xmx’ JVM 参数来指定 Java 堆大小。如果要将应用程序移植到容器中,您可能想知道如何在容器的世界中配置 Java 堆大小?有什么最佳实践吗?在本文中,我们将讨论可用于指定 Java 堆大小的可能的 JVM 参数以及选择的最佳选项。

有 3 个不同的选项可以指定容器中的最大 Java 堆大小。他们是:

  1. -XX:MaxRAMFraction, -XX:MinRAMFraction

  2. -XX:MaxRAMPercentage, -XX:MinRAMPercentage

  3. -Xmx

让我们讨论一下这些 JVM 论点,它们的优点和缺点。

  1. -XX:MaxRAMFraction, -XX:MinRAMFraction
    支持的版本
    ‘-XX:MaxRAMFraction’、‘-XX:MinRAMFraction’ JVM 参数仅支持从 Java 8 更新 131 到 Java 8 更新 190。因此,如果您使用的是任何其他版本的 JDK,则不能使用此选项。

它是如何工作的?
假设您已为容器分配了 1 GB 的内存,那么如果配置 -XX:MaxRAMFraction=2,则大约 ~512GB(即 1GB 的 1/2)将分配给您的 Java 堆大小。

如果要使用“-XX:MaxRAMFraction”JVM 参数,请确保同时传递这两个附加的 JVM 参数以及“-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap”。如果传递这两个 JVM 参数,则 JVM 将从容器的内存大小派生堆大小值。否则,它将从基础主机的内存大小派生堆大小值。

docker run -m 1GB openjdk:8u131 java -XX:+UnlockExperimentalVMOptions

-XX:+UseCGroupMemoryLimitForHeap
-XX:MaxRAMFraction=2 -XshowSettings:vm -version VM settings:
Max. Heap Size (Estimated): 494.94M

在这里,您可以看到 docker 容器的内存何时设置为“1GB”(即 -m 1GB)和“-XX:MaxRAMFraction=2”。根据此设置,JVM 分配的最大堆大小为 494.9MB(大约是 1GB 大小的一半)。

注: ‘-XX:MaxRAMFraction’ 和 ‘-XX:MinRAMFraction’ 都用于确定最大 Java 堆大小。JDK 开发团队本可以给一个比“-XX:MinRAMFraction”更好的名字。这个名字让我们认为,'-XX:MinRAMFraction’参数用于配置最小堆大小。但事实并非如此。要了解有关它们差异的更多信息,请阅读本文。

它的局限性是什么?
以下是这种方法的缺点。

一个。假设要配置 docker 内存大小的 40%,那么我们必须设置 ‘-XX:MaxRAMFraction=2.5’。当您传递 2.5 作为值时,JVM 将不会启动。这是因为“-XX:MaxRAMFraction”只能采用整数值,而不能采用十进制值。请参阅以下 JVM 无法启动的示例。


# 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' 
Error: Could not create the Java Virtual Machine. 
Error: A fatal exception has occurred. Program will exit.

b.在此选项中,Java 应用程序的堆大小将派生自容器的内存大小(因为它是基于分数的)。假设您的应用程序需要 1GB 的堆大小才能获得最佳性能,并且如果容器配置为以小于 1GB 的内存大小运行,则您的应用程序仍将运行。尽管如此,它仍将受到性能特征不佳的影响。

c.此参数在现代 Java 版本中已被弃用。仅从 Java 8 更新 131 到 Java 8 更新 190 支持它。

  1. -XX:MaxRAMPercentage, -XX: MinRAMPercentage
    支持的版本
    Java 8 更新 191 及更高版本支持 ‘-XX:MaxRAMPercentage’、‘-XX: MinRAMPercentage’ JVM 参数。因此,如果您运行在较旧的 JDK 版本上,则不能使用此 JVM 参数。

它是如何工作的?
假设您已为容器分配了 1 GB 的内存,那么如果配置 -XX:MaxRAMPercentage=50,则大约 512GB(即 1GB 的 1/2)将分配给您的 Java 堆大小。

# docker run -m 1GB openjdk:10 java -XX:MaxRAMPercentage=50 -XshowSettings:vm -version 
VM settings:     
Max. Heap Size (Estimated): 494.94M     
Using VM: OpenJDK 64-Bit Server VM 

您可以看到 docker 容器的内存何时设置为“-m 1GB”和“-XX:MaxRAMPercentage=50”。根据此设置,JVM 将最大堆大小分配为 494.9MB(大约是 1GB 的一半)。

注意: ‘-XX:MaxRAMPercentage’ 和 ‘-XX:MinRAMPercentage’ 都用于确定最大 Java 堆大小。JDK开发团队本可以给一个比“-XX:MinRAMPercentage”更好的名字。这个名字让我们认为,'-XX:MinRAMPercentage’参数用于配置最小堆大小。但事实并非如此。要了解有关它们差异的更多信息,请阅读本文。

注意:在互联网上的几篇文章中,提到在传递 ‘-XX:MaxRAMPercentage’、‘-XX:InitialRAMPercentage’、‘-XX:MinRAMPercentage’ 时需要传递 ‘-XX:+UseContainerSupport’ JVM 参数。实际上,事实并非如此。‘-XX:+UseContainerSupport’ 在 JVM 中由默认参数传递。因此,您不需要显式配置它。

有什么限制?
以下是此方法的局限性。

一个。旧版本的 Java 不支持此参数。只有 Java 8 更新 191 支持它。

容器的内存大小将派生 B。在此选项中,Java 应用程序的堆大小(因为它是基于百分比的)。如果应用程序需要 1GB 的堆大小才能获得最佳性能,并且容器配置为以小于 1GB 的内存大小运行,则应用程序仍将运行。尽管如此,它仍将受到性能特征不佳的影响。

  1. -Xmx
    支持的版本:
    所有版本的 Java 都支持“-Xmx”

它是如何工作的?
使用“-Xmx”JVM 参数,您可以指定细粒度的特定大小,例如 512MB、1024MB。

在这里,您可以看到非容器(传统物理服务器世界)支持的 -Xmx:

java -Xmx512m -XshowSettings:vm -version

VM settings:
Max. Heap Size: 512.00M
Ergonomics Machine Class: client
Using VM: OpenJDK 64-Bit Server VM

在这里,您可以看到容器世界中 java 8 update 131 版本中支持的 -Xmx:

docker run -m 1GB openjdk:8u131 java -Xmx512m -XshowSettings:vm -version VM

VM settings:
Max. Heap Size: 512.00M
Ergonomics Machine Class: client
Using VM: OpenJDK 64-Bit Server VM

在这里你可以看到 -Xmx to 在容器世界的 java 10 版本中支持:

docker run -m 1GB openjdk:10 java -Xmx512m -XshowSettings:vm -

version
VM settings:
Max. Heap Size: 512.00M
Using VM: OpenJDK 64-Bit Server VM

有什么限制?
一个。如果要分配的“-Xmx”超过容器的内存大小,则应用程序将遇到“java.lang.OutOfMemoryError: kill process or sacrifice child”。

最佳实践
无论您使用什么选项来配置堆大小(即 -XX:MaxRAMFraction、-XX:MaxRAMPercentage、-Xmx),请始终确保为容器分配的内存(即“-m”)至少比堆大小值多 25%。假设已将 -Xmx 值配置为 2GB,则将容器的内存大小配置为至少为 2.5GB。即使 Java 应用程序是唯一要在容器上运行的进程,也要执行此操作。因为很多工程师认为 Java 应用程序不会消耗超过 -Xmx 值。事实并非如此。除了堆空间之外,您的应用程序还需要 Java 线程、垃圾回收、元空间、本机内存、套接字缓冲区的空间。所有这些组件都需要在分配的堆大小之外的额外内存。除此之外,其他小进程(如 APM 代理、Splunk 脚本等)也需要内存。要了解有关它们的更多信息,请观看此快速的“JVM 内存”视频剪辑。
如果在容器中仅运行 Java 应用程序*,则将初始堆大小(即使用 ‘-XX:InitialRAMFraction’、‘-XX:InitialRAMPercentage’、-Xms) 之一设置为与最大堆大小相同的大小。设置初始堆大小和最大堆具有某些优点。其中之一是:您将产生更短的垃圾回收暂停时间。因为每当堆大小从初始分配的大小增长时,它就会暂停 JVM。当您将初始堆大小和最大堆大小设置为相同时,可以规避它。除此之外,如果你有一个分配不足的容器的内存大小,那么 JVM 甚至不会启动(这比在事务运行中遇到 OutOfMemoryError 要好)。
在我的人事看来,我更喜欢使用 -Xmx 选项而不是 -XX:MaxRAMFraction、-XX:MaxRAMPercentage 选项来指定容器世界中的 Java 堆大小,原因如下:
我不希望容器的大小决定我的 java 应用程序的堆大小。你的体型应该决定你是穿“小号”还是“中号”或“大号”T恤,而不是相反。你不想让一个 6 英尺高的男人穿着一件“小”码的 T 恤。内存大小在决定应用程序性能方面起着关键作用。它会影响您的垃圾回收行为和性能特征。您不希望该因素由容器的内存设置决定。
使用“-Xmx”,我可以设置细粒度/精度值,例如 512MB、256MB。
所有 Java 版本都支持 -Xmx。
如果您研究容器的新设置是否会影响应用程序的垃圾回收和性能特征,这将有所帮助。要研究垃圾回收行为,您可以使用 GCeasy、IBM GC & Memory Visualizer、HP JMeter 等免费工具。

  • 34
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小徐博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值