必须显式限制容器和JVM资源:容器层用--memory=2g--memory-swap=2g,JVM层设-Xmx1200m-XX:MaxMetaspaceSize=256m等,并启用-XX:+UseContainerSupport,配合--cpus=1.5及GC线程调优,避免OOM Kill与CPU抢占。

Java 生产环境里,单个容器的内存和 CPU 必须显式限制,否则 JVM 会按宿主机规格自动配置堆和线程数,极易触发 OOM Kill 或 CPU 抢占,导致服务频繁重启或雪崩。
内存限制:必须同时约束容器和 JVM
只设 --memory 不够,JVM 默认读取宿主机内存(比如 64G),哪怕容器只分配了 2G,-Xmx 也可能被设成 16G,直接被内核杀掉。
-
容器层:用
--memory=2g --memory-swap=2g,禁用 swap 防止不可控内存溢出 -
JVM 层:必须显式指定堆上限,且留出非堆空间余量。例如容器 2G 内存,建议
-Xmx1200m -XX:MaxMetaspaceSize=256m -XX:MaxDirectMemorySize=256m -Xss256k -
验证方式:进容器执行
cat /sys/fs/cgroup/memory/memory.limit_in_bytes看是否生效;运行docker stats观察 RSS 是否稳定在限制值内
CPU 限制:优先用 --cpus,慎用 --cpu-shares
--cpu-shares 是相对权重,只在争抢时起作用,生产环境难以保障确定性。而 --cpus 是硬上限,更符合稳定性要求。
- 设
--cpus=1.5表示最多使用 1.5 个逻辑核心(如宿主机有 8 核,该容器最多占用 1.5 核的算力) - JVM 会感知不到这个限制,需手动调优 GC 线程数:
-XX:ParallelGCThreads=3 -XX:ConcGCThreads=2(按实际分配的 CPU 数反推) - 验证方式:运行
docker stats查看 CPU % 是否长期不超设定值;或用top -H -p $(pgrep java)检查线程数是否合理
部署方式:命令行、Compose、API 三选一
生产环境推荐统一通过 CI/CD pipeline 注入参数,避免手工操作遗漏。
立即学习“Java免费学习笔记(深入)”;
-
docker run:适合调试,例如
docker run -d --name app --cpus=1 --memory=2g -e JAVA_OPTS="-Xmx1200m" my-java-app -
docker-compose.yml(仅 Swarm 模式生效):
deploy: resources: limits: cpus: '1.0' memory: 2G -
Docker Java API:代码中构造
HostConfig,如hostConfig.withMemory(2L * 1024 * 1024 * 1024).withNanoCpus(1_000_000_000L)
关键避坑点
这些细节不处理,限制就形同虚设:
- JDK 版本低于 8u131 或 10+ 未启用
+UseContainerSupport(默认开启),JVM 就无法识别 cgroups 限制 - 没设
-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap(旧版 JDK 必须加) - 忽略容器系统开销(约 10%~15%),把全部内存都划给
-Xmx,剩余空间不够元空间或直接内存,照样 OOM - 监控缺失:必须配合
docker stats或 Prometheus + cAdvisor 做告警,比如内存持续 >90% 或 CPU 突增 3 倍以上


















