容器限额四 G,Java 服务启动没多久就被杀掉,重启循环,可进容器用工具看到的堆占用才两 G 多一点。

真正麻烦的地方在于,几个原因的现象几乎一样。老版本 JDK 不识别容器限制,按宿主机内存计算默认堆大小。另一种情况是堆外内存和元空间不在堆统计范围内,很容易超限。

不容易想到的是,容器的限制值和请求值差距太大,调度结果不可预期。

先确认容器实际被限制的内存

cat /sys/fs/cgroup/memory.max

显式指定堆大小

java -Xms2g -Xmx2g -XX:MaxMetaspaceSize=256m -jar app.jar

限制直接内存上限

java -XX:MaxDirectMemorySize=256m -jar app.jar

末了看容器是否因内存被杀

docker inspect -f '{{.State.OOMKilled}}' 容器名

改之前先确认了最近有没有人动过配置,避免白查一遍。

恢复的判定其实很直接。容器连续运行数天不再被杀,堆占用与限额之间留有合理余量,启动日志正常。

容易忽略的是,堆外内存、线程栈和元空间都要算进容器限额,只调堆参数经常还是超;换成识别容器限额的 JDK 能省一半事。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。

作者 9823189