避坑指南

从 java 10 开始,JVM 在分配堆大小的时候,会考虑容器内存限制,而不是主机配置。

对应 JVM 参数为默认开启


java  -XX:+UseContainerSupport

可以用过此方法禁用


java  -XX:-UseContainerSupport

此参数已向后移植到 Java 8: 文档地址

如果不修改 JVM 内存参数,则默认最大使用总内存的四分之一。

在容器中可以设置一下参数进行更细粒度的内存控制。

  • -XX:InitialRAMPercentage

  • -XX:MaxRAMPercentage

  • -XX:MinRAMPercentage

值介于 0.0 到 100.0 之间,MaxRAMPercentage 默认值为 25.0。

基于 tomcat 容器下 JVM 配置

可以通过设置容器环境变量 JAVA_OPTS


containers:

- name: java_app

env:

- name: JAVA_OPTS

value: "xxxxxxx"

基于 jdk 容器的 Spring boot 下 JVM 配置

可以通过设置容器环境变量 JAVA_TOOL_OPTIONS


containers:

- name: java_app

env:

- name: JAVA_TOOL_OPTIONS

value: "xxxxxxx"

实战

设置最大容量为总内存的 80%,且使用 k8s 限制容器最大内存为 500M

image-20220616170225999

可见容器正常运行

image-20220616165752164

接下来模拟一个比较苛刻的条件,我们将内存限制为 200M

image-20220616165835566

可以看到容器未能正常启动

image-20220616165936394

查看时间可见为 pod 使用的内存已经超过 k8s 的限制,因此 OOM killed 了

image-20220616170012740

总结 使用 k8s limitsjvm -XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0 的配合可以做到对java 程序更加细粒度的控制,无需针对每个程序进行 jvm 内存的计算,仅需控制 k8s limits 即可控制对应程序的内存控制。

参考资料

https://stackoverflow.com/questions/54516988/what-does-usecontainersupport-vm-parameter-do

https://www.oracle.com/java/technologies/javase/8u191-relnotes.html