JVM默认的最大Heap大小是系统内存的1/4。在java的早期版本中(小于1.8.131),不支持读取cgroup的限制。默认是从/proc/目录读取可用内存。容器中的/proc目录默认是挂载的宿主机的内存目录。即java 读取的到可用的内存是宿主机的内存。那么自然会导致进程超出容器limit 限制的问题。
正确设置Java内存防止容器OOM Killer
获取容器内存限制,在启动参数中设置堆内存大小
#!/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。导致内存的使用率不高。