容器 OOM 是什么
给容器设置了内存上限后,进程申请的内存超过上限时,内核会触发 OOM 终止流程,通常直接杀掉容器内最占内存的进程,容器随之退出。识别特征很明确:退出码是 137,容器状态里带 OOM 标记。处理不是简单地把上限调大,而是先判断用量是正常峰值还是持续增长,再决定调限额、修内存泄漏还是调整运行时堆参数。
基本信息
| 典型退出码 | 137,表示 128 加 SIGKILL |
|---|---|
| 判定字段 | .State.OOMKilled 为 true |
| 内存上限字段 | .HostConfig.Memory(字节) |
| 宿主侧记录 | dmesg 中与内存终止相关的记录 |
| 相关参数 | --memory 设上限、--memory-swap 控制交换、--oom-kill-disable 关闭终止(谨慎使用) |
| 观察工具 | docker stats、容器内应用的自己指标 |
典型使用场景
- 服务反复重启且日志无异常:确认是否被内存终止
- 大内存任务中途失败:核对峰值是否超过限额
- 排查内存泄漏:观察限额固定而用量持续爬升
- 容量规划:根据稳定用量设置合理上限,避免一味放大
- Java 类服务调参:上限与堆参数需要配套调整
判定与取证
判定与取证
# 一、退出码与 OOM 标记:两条要一起看
docker inspect -f 'exit={{.State.ExitCode}} oom={{.State.OOMKilled}} limit={{.HostConfig.Memory}}' api
# 二、容器与宿主的事件记录
docker events --filter container=api --filter event=oom --since 24h
dmesg | grep -i -E 'oom|killed process' | tail -20
# 三、用量观察:看长期趋势而不是单点
docker stats --no-stream api
# 四、限额与交换空间的配置
docker run -d --memory 512m --memory-swap 1g --name api app/api:1.4.2结果判读
| 线索 | 结论 | 处理方向 |
|---|---|---|
| 137 且 OOMKilled=true | 容器内存超限 | 调上限或修内存增长 |
| 137 且 OOMKilled=false | 宿主内存紧张或人为终止 | 查看宿主日志与操作记录 |
| 用量锯齿状上升后归零 | 周期性任务峰值超限 | 错峰或提高上限 |
| 用量缓慢持续上升 | 疑似内存泄漏 | 抓取长期样本定位 |
| 限额很高仍被终止 | 宿主整体容量不足 | 评估宿主与同机服务 |
调整与验证
调整与验证
# 调大上限后重建容器(改运行参数必须重建)
docker rm -f api
docker run -d --memory 1g --name api app/api:1.4.2
# 验证限额已生效:Memory 字段应等于新上限
docker inspect -f '{{.HostConfig.Memory}}' api
# 压测期间持续观察,确认稳定用量与峰值都有余量
docker stats --no-stream api关闭 OOM 终止能力(--oom-kill-disable)只在容器已设置内存上限且有明确理由时才讨论,它会让内存压力转嫁给宿主其他进程,通常不是好选择。
按整机内存推导堆大小的运行时会忽略容器限额:Java、Node 之类的服务在被限内存后仍可能申请过多内存,限制上限时要同时调小应用的堆参数。