【问题标题】:Pod sizing with Actuator metrics jvm.memory.max使用执行器指标 jvm.memory.max 调整 Pod 大小
【发布时间】:2026-01-12 20:35:01
【问题描述】:

我正在尝试使用执行器指标信息来调整我们的 pod 的大小。用下面的K8资源配额配置;

resources:
 requests:
  memory: "512Mi"
 limits:
  memory: "512Mi"

我们观察到 jvm.memory.max 返回 ~1455 mb。我知道这个值包括堆和非堆。进一步深入研究 api (jvm.memory.max?tag=area:nonheap) 和 (jvm.memory.max?tag=area:heap) 分别得到 ~1325mb 和 ~129mb。

显然,当非堆设置为最大值时,该值大于 K8 限制,容器最终必然会被杀死。但是为什么jvm(非堆内存)不受容器内存配置(K8中配置)的限制?

上述观察结果适用于 java 8 和 java 11。下面的博客讨论了 java 8 的实验选项,其中讨论了 CPU 和堆配置,但没有提及非堆。在调整 pod 大小时需要考虑哪些建议?

-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap Source

【问题讨论】:

  • 你找到答案了吗?寻找相同问题的答案

标签: spring-boot docker kubernetes


【解决方案1】:

Java 8 有一些标志可以帮助运行时以更加容器感知的方式运行:

java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -jar app.jar

如果将最大容器内存限制设置为 512 MB,为什么会获得 129 MB 的最大 JVM 堆内存?所以答案是JVM中的内存消耗包括堆内存和非堆内存。类元数据、JIT 编译代码、线程堆栈、GC 和其他进程所需的内存取自非堆内存。因此,JVM会根据cgroup资源限制,预留一部分内存供非堆使用,以保证系统稳定性。 非堆内存的确切数量可能有很大差异,但如果您正在进行资源规划,可以肯定的是,堆大约占 JVM 总内存的 80%。因此,如果您将设置的最大堆设置为 1000 MB,您可以预期整个 JVM 可能需要大约 1250 MB。

JVM 读取到容器被限制为 512M,并创建了一个最大堆大小为 ~129MB 的 JVM。正好是 JDK 人体工程学页面中定义的容器内存的 1/4。

如果您深入了解JVM Tuning guide,您将看到以下内容。

除非在命令行中指定了初始和最大堆大小,否则它们是根据机器上的内存量计算的。默认的最大堆大小是物理内存的四分之一,而初始堆大小是物理内存的 1/64。分配给年轻代的最大空间量是总堆大小的三分之一。

你可以找到更多关于它的信息here

【讨论】: