Java -XX:MaxRAMFraction=1在集装箱环境中安全生产吗?

Java -XX:MaxRAMFraction=1在集装箱环境中安全生产吗?,java,docker,jvm,Java,Docker,Jvm,Java 8/9带来了对-XX:+UseCGroupMemoryLimitForHeap的支持(使用-XX:+UnlockExperimentalVMOptions)。这将-XX:MaxRAM设置为cgroup内存限制。默认情况下,JVM分配大约25%的最大RAM,因为-XX:MaxRAMFraction默认为4 例如: MaxRAM = 1g MaxRAMFraction = 4 JVM is allowed to allocate: MaxRAM / MaxRAMFraction = 1g

Java 8/9带来了对
-XX:+UseCGroupMemoryLimitForHeap
的支持(使用
-XX:+UnlockExperimentalVMOptions
)。这将
-XX:MaxRAM
设置为cgroup内存限制。默认情况下,JVM分配大约25%的最大RAM,因为
-XX:MaxRAMFraction
默认为4

例如:

MaxRAM = 1g
MaxRAMFraction = 4
JVM is allowed to allocate: MaxRAM / MaxRAMFraction = 1g / 4 = 256m
对于(通常)由单个JVM进程组成的部署来说,仅使用25%的配额似乎是浪费。所以现在人们设置
-XX:MaxRAMFraction=1
,因此理论上允许JVM使用100%的最大内存

对于1g示例,这通常会导致堆大小在900m左右。这似乎有点高——JVM或其他东西(如远程shell或进程外任务)没有太多空闲空间


那么这个配置(
-XX:+UnlockExperimentalVMOptions-XX:+UseCGroupMemoryLimitForHeap-XX:MaxRAMFraction=1
)是否被认为对产品安全,甚至是最佳实践?或者我还是应该手工挑选
-Xmx
-Xms
-Xss
等等?

我们做了一些简单的测试,结果表明设置
-XX:MaxRAM=$QUOTA
-XX:MaxRAMFraction=1
会导致容器在负载下死亡。JVM分配的堆超过900M,这太多了<代码>-XX:MaxRAMFraction=2似乎安全(ish)

请记住,您可能希望为其他进程留出空间,例如在容器中获取调试shell(
docker exec
)或诊断


编辑:我们已经把所学的详细内容写在了一篇文章中。货币报价:

TL'DR: Java内存管理和配置仍然很复杂。尽管自Java9/8u131以来,JVM可以读取cgroup内存限制并相应地调整内存使用,但它并不是一颗金弹。您需要知道
-XX:+UseCGroupMemoryLimitForHeap
的作用,并且需要为每个部署微调一些参数。否则,您可能会浪费资源和金钱,或者在最坏的时候让您的容器被杀死<代码>-XX:MaxRAMFraction=1特别危险。Java10+带来了很多改进,但仍然需要手动配置。为了安全起见,对你的东西进行负载测试

最优雅的解决方案是升级到Java10+。Java 10反对
-XX:+UseCGroupMemoryLimitForHeap
(11),并引入了
-XX:+UseContainerSupport
(12),后者取代了它。它还引入了
-XX:MaxRAMPercentage
(13),它的值介于0和100之间。这允许对JVM允许分配的RAM量进行细粒度控制。由于默认情况下启用了
+UseContainerSupport
,因此所有操作都应开箱即用


编辑#2:我们有关于
-XX:+UseContainerSupport

Java10引入了
+UseContainerSupport
(默认启用),这使得JVM在容器环境中使用正常的默认值。自8u191以来,该功能被后移植到Java8,这可能会允许大量的Java部署在野外正确配置内存

最近的oracle-jdk-8(8u191)提供了以下选项,允许Docker容器用户对Java堆使用的系统内存量进行更细粒度的控制:

-XX:InitialRAMPercentage
-XX:MaxRAMPercentage
-XX:MinRAMPercentage
添加了三个新的JVM选项以允许Docker容器用户 以获得对系统内存量的更细粒度控制 将用于Java堆的:

-XX:InitialRAMPercentage
-XX:MaxRAMPercentage
-XX:MinRAMPercentage
-XX:初始斜率 -XX:MaxRAMPercentage -XX:MinRAMPercentage这些选项替换不推荐使用的分数形式(-XX:InitialRAMFraction,-XX:MaxRAMFraction,和 -XX:最小分数)


参见相关:你读了吗?我读了。有人在评论中问到为堆分配超过90%的可用RAM是否安全,作者回答说“假设MaxRAMFraction=1仍将为其他非堆内存留出一些空间。不过,我还没有做过广泛的测试”。这似乎不是一个明确的答案。我知道您要求的是Java8/9,但仅供参考的Java10添加了新选项-XX:MaxRAMPercentage,它更合理,并提供了更大的灵活性来指定最大堆大小。因此,您可以说-XX:MaxRAMPercentage=80来告诉JVM使用80%的容器内存作为堆。默认的最大堆大小也更接近容器内存限制。我们发现,非堆内存分配往往是相当固定的。我们使用SpringBoot2进行了测试,我们必须将分数设置为4,如果我们的内存在500MB左右,但是当我们达到1G时,我们可能会下降。对于更大的容器,90%的空间足以让应用程序正常运行。(容器中有4gb内存。)每个容器有4gb内存?您是否发现这是优化性能的最佳方法?我一直在尝试增加负载,但很难找到正确的容器数量和每个容器的内存。括号中的数字意味着什么?这些标志在JDK 10+中可用,但是,
-XX:+UseContainerSupport
现在在
8u191
@Fleshgrinder中可用。我编写了一个简单的演示来测试它,它在jdk-8u191上工作,看我试过
-XX:MaxRAMPercentage=75
,它给了我一个错误,也许分数是必需的?!?同样有趣的是,bug本身没有提到作为
8u191
@Fleshgrinder的一部分的修复,这可能是不合理的,但在我的测试中,百分比必须是一个浮点数,比如75.0,另外一点应该提到的是,
-XX:MaxRAMPercentage
-XX:MinRAMPercentage
应该一起使用。在
8u191中似乎有点破绽,可以(至少)在11中按预期使用它。始终同时使用max和min的要求也没有什么意义。