如何解决JAVA进程内存占用超过容器自身的资源限制,导致容器重启的问题?

故障前,java进程占3.9g左右,基于以上问题描述,我们想了解:
1. java 进程的内存占用和 JVM xmx 配置的大小是否有确定的比例关系;
2.是否可通过某种配置手段限制 java 进程的内存占用;
3.针对 container 部署的场景,container 内存资源限额与 JVM 堆内存大小有没有配置比例的最佳实践。
环境信息如下:
K8S版本:1.14.6
DOCKER版本:18.9.6
container资源限额:内存4096Mi,CPU2000m
DOCKER内操作系统版本:CentOS linux release 7.4.1708(Core)
JDK版本:ZULU 8.33.0.1-jdk8.0.192-linux_x64
jvm参数:-Xms3072m -Xmx3072m -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -Xloggc:/tomcat/apache-tomcat-8.5.40/gclogs/gc.log.$(date -u +%Y-%m-%d-%H-%M) -verbose:gc -XX:+PrintGCDateStamps
JVM GC log 在 oom kill 前未见异常。

3回答

xiaoping378xiaoping378  系统架构师 , 光大科技有限公司
晓风赞同了此回答
1. 没有比例,依具体业务定,java进程占用内容主要是堆内存和堆外内存,严格说还要包含文件缓存内存。2. 不能,java业务代码如果有 Unsafe.allocateMemory() 类的方法,直接脱离了vm的控制。3.  一般 容器设置成堆内存的1.3-1.5倍就可以了,特殊业务还要增加,比如ES都是2倍起。...显示全部

1. 没有比例,依具体业务定,java进程占用内容主要是堆内存和堆外内存,严格说还要包含文件缓存内存。
2. 不能,java业务代码如果有 Unsafe.allocateMemory() 类的方法,直接脱离了vm的控制。
3.  一般 容器设置成堆内存的1.3-1.5倍就可以了,特殊业务还要增加,比如ES都是2倍起。

收起
 2020-06-19
浏览1260
namelessnameless  技术总监 , 某云计算厂商
1、没有确定比例,一般根据业务需求定;2、没有3、可以设置2倍 综上几个问题,建议对业务进行下压测,可以看下是哪些线程或进程没有及时释放,看是否有内存泄漏。显示全部

1、没有确定比例,一般根据业务需求定;
2、没有
3、可以设置2倍

综上几个问题,建议对业务进行下压测,可以看下是哪些线程或进程没有及时释放,看是否有内存泄漏。

收起
 2020-06-22
浏览1109
晓风晓风  研发工程师 , 光大科技
JVM默认的最大Heap大小是系统内存的1/4。在java的早期版本中(小于1.8.131),不支持读取cgroup的限制。默认是从/proc/目录读取可用内存。容器中的/proc目录默认是挂载的宿主机的内存目录。即java 读取的到可用的内存是宿主机的内存。那么自然会导致进程超出容器limit 限制...显示全部

JVM默认的最大Heap大小是系统内存的1/4。在java的早期版本中(小于1.8.131),不支持读取cgroup的限制。默认是从/proc/目录读取可用内存。容器中的/proc目录默认是挂载的宿主机的内存目录。即java 读取的到可用的内存是宿主机的内存。那么自然会导致进程超出容器limit 限制的问题。

正确设置Java内存防止容器OOM Killer

  1. 获取容器内存限制,在启动参数中设置堆内存大小
    #!/bin/bash
    limit_in_bytes=$(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)
    # If not default limit_in_bytes in cgroup
    if [ "$limit_in_bytes" -ne "9223372036854771712" ]
    then
    limit_in_megabytes=$(expr $limit_in_bytes \/ 1048576)
    heap_size=$(expr $limit_in_megabytes - $RESERVED_MEGABYTES)
    export JAVA_OPTS="-Xmx${heap_size}m $JAVA_OPTS"
    echo JAVA_OPTS=$JAVA_OPTS
    fi
    exec catalina.sh run

2:在java版本8u131和9以后使用以下标志允许JVM基于容器限制进行垃圾收集

-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap

新问题:-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap后,docker没有被kill了。但fullGC很频繁,cpu大量占用在垃圾回收的工作上了。原因:默认的xmx的值为镜像上限内存的1/4,提前fullGC。导致内存的使用率不高。

收起
 2020-06-19
浏览1392

提问者

yin986软件架构设计师, 阳光保险集团

问题状态

  • 发布时间:2020-06-19
  • 关注会员:4 人
  • 问题浏览:3628
  • 最近回答:2020-06-22