-XX:MaxRAMFraction = 1是否适合在集装箱环境中生产?

时间:2018-04-16 09:45:05

标签: 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 / 4 = 256m

仅使用25%的配额对于部署(通常)由单个JVM进程组成的部署而言似乎是浪费。所以现在人们设置-XX:MaxRAMFraction=1,因此理论上允许JVM使用100%的MaxRAM。

对于1g示例,这通常导致堆大小约为900米。这似乎有点高 - JVM或其他东西(如远程shell或进程外任务)没有太多空间。

这种配置(-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1)被认为是安全的,甚至是最佳做法吗?或者我还应该亲自挑选-Xmx-Xms-Xss等等吗?

2 个答案:

答案 0 :(得分:18)

我们做了一些简单的测试,结果显示设置-XX:MaxRAM=$QUOTA-XX:MaxRAMFraction=1会导致已装载的已杀死容器。 JVM分配超过900M的堆,这太多了。 -XX:MaxRAMFraction=2似乎是安全的(ish)。

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

编辑:我们已经在article中详细了解了我们所学到的内容。钱报价:

  

<强> TL'DR:   Java内存管理和配置仍然很复杂。虽然自Java 9 / 8u131以来JVM可以读取cgroup内存限制并相应地调整内存使用量,但它并不是一个金子弹。您需要知道-XX:+UseCGroupMemoryLimitForHeap的作用,并且需要为每个部署微调一些参数。否则,您可能会浪费资源和金钱,或者在最糟糕的时间让您的集装箱死亡。 -XX:MaxRAMFraction=1特别危险。 Java 10+带来了很多改进,但仍需要手动配置。为了安全起见,请加载测试你的东西。

  

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

答案 1 :(得分:8)

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

var port = new SerialPort();
// LoggingStream inherits Stream, implements IDisposable, needen abstract methods and 
// overrides needen virtual methods. 
Stream portStream = new LoggingStream(port.BaseStream);
portStream.Write(...); // Logs write buffer.
portStream.Read(...); // Logs read buffer.
  

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

     

-XX:InitialRAMPercentage   -XX:MaxRAMPercentage   -XX:MinRAMPercentage这些选项替换了不建议使用的小数形式(-XX:InitialRAMFraction,-XX:MaxRAMFraction和   -XX:MinRAMFraction)。

请参见https://www.oracle.com/technetwork/java/javase/8u191-relnotes-5032181.html