根本解是在容器启动时显式设置内存硬限制并让JVM主动感知该限制。必须设--memory硬限制,否则JVM按宿主机内存估算堆大小易超限被杀;需启用UseContainerSupport、避免-Xmx覆盖、配合memory-reservation软限制,并验证cgroup与JVM堆配置生效。

根本解是:**在容器启动时显式设置内存硬限制,并让 JVM 主动感知该限制,而非依赖宿主机内存推算堆大小**。
必须设硬限制(--memory)
不设 --memory,容器就无内存边界,内核会按宿主机总内存估算 JVM 堆(如 1/4),极易超限被杀。哪怕应用本身只用几百 MB,只要 JVM 自行分配超过可用物理内存,OOM Killer 就会介入。
- 示例:
docker run -m 1g openjdk:17-jre ...—— 强制容器最多用 1GB 物理内存 - 对应 Docker Compose:
deploy.resources.limits.memory: 1G
JVM 必须启用容器感知(UseContainerSupport)
旧版 JDK(如 8u191 前)默认无视 cgroups 限制;新版 JDK 默认开启,但需确认未被覆盖:
- JDK 8u191+ / JDK 10+:加
-XX:+UseContainerSupport(已默认启用,无需显式加) - 禁用
-Xmx固定值,或确保其 ≤ 容器内存 × 75%(如容器 1G,-Xmx768m) - 避免混用:
-Xmx会覆盖容器感知逻辑,导致 JVM 仍按宿主机内存分配
补充软限制提升弹性(--memory-reservation)
仅设硬限制不够——系统压力下无法提前回收内存。软限制触发内核主动回收,降低 OOM 触发概率:
-
--memory-reservation=768m(硬限制 1G 时推荐设为 70%~80%) - 等效于 cgroup 的
memory.soft_limit_in_bytes,让内核在内存紧张时优先压缩该容器内存
验证是否生效
容器运行后立即检查,别等出事:
-
docker inspect <cid> | grep -i memory→ 确认Memory和MemoryReservation已写入 - 进容器执行:
cat /sys/fs/cgroup/memory/memory.limit_in_bytes应返回 1073741824(1G) - 查 JVM 实际堆大小:
jstat -gc <pid>或启动时加-XX:+PrintGCDetails,确认初始/最大堆接近软硬限制比例

















