如果容器资源没有设置任何 limits 并且Java没有设置额外参数的话,Java应用会默认使用宿主机 1/4 的内存作为 MaxHeapSize诉求项目存在JVM内存溢出,排查发现JVM默认占用Pod资源的1/4,给定4g,占用了1g;
1、JVM内存占用分析
- 未分配JVM内存时的使用情况(2G)
1. 检查JDK是否支持UseContainerSupport
首先查看使用JDK版本是否支持 UseContainerSupport 参数,如果支持该参数,则JVM会自动读取容器限制的内存值,读取文件:/sys/fs/cgroup/memory/memory.limit_in_bytes
该参数在 Java 8u191+,10以及更高的版本中支持
- 检查方法(bool值,返回true表示支持,反之不支持):
$ java -XX:+PrintFlagsFinal -version | grep UseContainerSupport
bool UseContainerSupport = true {product}
openjdk version "1.8.0_342"
OpenJDK Runtime Environment (build 1.8.0_342-b07)
OpenJDK 64-Bit Server VM (build 25.342-b07, mixed mode)
2. 支持UseContainerSupport
-XX:MaxRAMPercentage
参数来配置JVM可用容器限制的资源百分比,默认是25.0 ;取值范围是 0.0 到 100.0
- 检查当前堆内存的大小:(2147483648Bytes=2097152KB=2048MB=2GB)
$ java -XX:+PrintFlagsFinal -version | grep MaxHeapSize
uintx MaxHeapSize := 2147483648 {product}
openjdk version "1.8.0_342"
OpenJDK Runtime Environment (build 1.8.0_342-b07)
OpenJDK 64-Bit Server VM (build 25.342-b07, mixed mode)
- 修改JVM可用Pod容器资源限制的百分比80:(6878658560Bytes=6717440KB=6560MB=6.40625GB)
java -XX:MaxRAMPercentage=80.0 -XX:+PrintFlagsFinal -version | grep MaxHeapSize
uintx MaxHeapSize := 6878658560 {product}
openjdk version "1.8.0_342"
OpenJDK Runtime Environment (build 1.8.0_342-b07)
OpenJDK 64-Bit Server VM (build 25.342-b07, mixed mode)
1)修改Dockerfile并在部署时添加环境变量来验证
由于之前的Dockerfile中的变量没有设置该参数所以需要设置环境变量来替代,以后直接在Dockerfile中设置合适不用在动态配置环境变量:建议值:
<font style="color:#E8323C;">-XX:InitialRAMPercentage=70.0 -XX:MaxRAMPercentage=70.0</font>
或者<font style="color:#E8323C;">-XX:InitialRAMPercentage=75.0 -XX:MaxRAMPercentage=75.0</font>
不能是整数:70、75(可能是jdk的一个bug)
2)建议配置参数
-XX:+UseContainerSupport -XX:InitialRAMPercentage=70.0 -XX:MaxRAMPercentage=70.0 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/admin/nas/gc-${POD_IP}-$(date '+%s').log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/nas/dump-${POD_IP}-$(date '+%s').hprof
# 配置到tmp目录中
-XX:+UseContainerSupport -XX:InitialRAMPercentage=70.0 -XX:MaxRAMPercentage=70.0 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/tmp/gc-${POD_IP}-$(date '+%s').log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/dump-${POD_IP}-$(date '+%s').hprof
-XX:+UseContainerSupport -XX:InitialRAMPercentage=70.0 -XX:MaxRAMPercentage=70.0 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/tmp/gc-${POD_IP}-$(date '+%s').log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/dump-${POD_IP}-$(date '+%s').hprof
🎯**说明** 应用程序出现OOM问题时,会触发Linux内核的OOM Killer机制。该机制能够监控占用过大内存,尤其是瞬间消耗大量内存的进程,然后它会强制关闭某项进程以腾出内存留给系统,避免系统立刻崩溃。
3. 不支持UseContainerSupport
-Xms2g -Xmx2g
配置JVM内存-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
配置占比
1)-Xms1000m -Xmx2000m
方式
⚠️弊端:每次修改Pod容器限制后都需要手动修改相关环境变量来更改配置
- 推荐参数
-Xms2048m -Xmx2048m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/admin/nas/gc-${POD_IP}-$(date '+%s').log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/nas/dump-${POD_IP}-$(date '+%s').hprof
其中Dump文件路径/home/admin/nas为NAS挂载目录:
- 当应用发生OOM时,会生成堆转储文件到NAS挂载目录,您可以利用ossutil工具,将该Dump文件下载到本地进行分析。具体操作,请参见通过日志上传下载诊断应用。
- -Xmx 参数即使设置了2000m,JVM也会分配比2000m多的内存,如果想将JVM完全限制在2000m以内,需要使用 -XX:MaxRAM 参数
2)-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
方式
⚠️弊端:对于 Java SE 8u121 以及之前的版本这些参数都不生效,只能通过
使用 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap 参数来让JVM读取容器限制 不过默认即使加上这两个参数,JVM也只会使用容器限制内存的 1/4 的量,可以再添加一个参数 -XX:MaxRAMFraction ,该参数表示使用可用内存的基数,默认是4 JVM可用最大heap内存=最大可用内存*1/MaxRAMFraction<font style="color:rgb(51, 51, 51);"> -Xms1000m -Xmx2000m </font>
这种方式进行限制
java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=2 -XX:+PrintFlagsFinal -version | grep MaxHeapSize
如果配置了 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap 参数,则JVM使用容器限制内存的 1/4,即4000m*1/4=1000m 如果配置了 -XX:MaxRAMFraction=2 ,则JVM使用容器限制内存的 1/2,即 4000m*1/2=2000m
:::color2 🎯设置 MaxRAMFraction 为1表示将容器所有内存分配给JVM,不建议这么做,需要给其他程序预留部分内存
Java 10 移除了 -XX:{Initial|Min|Max}RAMFraction 参数:::
:::color1 参考链接:
https://help.aliyun.com/document_detail/383255.html
https://blog.csdn.net/qq_34556414/article/details/121101809
https://www.cnblogs.com/xiaoqi/p/container-jvm.html
:::