container@进程oom分析

问题

容器运行一段时间发现有重启过,为什么重启找下原因?

env

  • centos7.8
  • docker

日志

如下一段 dmesg -T 的内核日志,显示了 Docker 容器因内存限制被 OOM 杀手(Out Of Memory Killer)终止 的过程。

[Wed May 28 23:55:16 2025] Hardware name: Alibaba Cloud Alibaba Cloud ECS, BIOS 2221b89 04/01/2014
[Wed May 28 23:55:16 2025] Call Trace:
[Wed May 28 23:55:16 2025]  [<ffffffff99fb1bec>] dump_stack+0x19/0x1f
[Wed May 28 23:55:16 2025]  [<ffffffff99facb4f>] dump_header+0x90/0x22d
[Wed May 28 23:55:16 2025]  [<ffffffff99fba710>] ? _raw_spin_trylock+0x50/0x50
[Wed May 28 23:55:16 2025]  [<ffffffff999cce16>] ? find_lock_task_mm+0x56/0xd0
[Wed May 28 23:55:16 2025]  [<ffffffff99a4a458>] ? try_get_mem_cgroup_from_mm+0x28/0x70
[Wed May 28 23:55:16 2025]  [<ffffffff999cd3a5>] oom_kill_process+0x2d5/0x4a0
[Wed May 28 23:55:16 2025]  [<ffffffff99a4e93c>] mem_cgroup_oom_synchronize+0x55c/0x590
[Wed May 28 23:55:16 2025]  [<ffffffff99a4dd90>] ? mem_cgroup_charge_common+0xc0/0xc0
[Wed May 28 23:55:16 2025]  [<ffffffff999cdca4>] pagefault_out_of_memory+0x14/0x90
[Wed May 28 23:55:16 2025]  [<ffffffff99faaf88>] mm_fault_error+0x6a/0x15b
[Wed May 28 23:55:16 2025]  [<ffffffff99fbfa61>] __do_page_fault+0x4a1/0x510
[Wed May 28 23:55:16 2025]  [<ffffffff99fbfbb6>] trace_do_page_fault+0x56/0x150
[Wed May 28 23:55:16 2025]  [<ffffffff99fbf112>] do_async_page_fault+0x22/0x100
[Wed May 28 23:55:16 2025]  [<ffffffff99fbb7e8>] async_page_fault+0x28/0x30
[Wed May 28 23:55:16 2025] Task in /docker/78d543660f71a779c906e792664dd8fb1910e0a108a8974f46bf68f4a1e85de9 killed as a result of limit of /docker/78d543660f71a779c906e792664dd8fb1910e0a108a8974f46bf68f4a1e85de9
[Wed May 28 23:55:16 2025] memory: usage 6291456kB, limit 6291456kB, failcnt 1109137
[Wed May 28 23:55:16 2025] memory+swap: usage 6291456kB, limit 12582912kB, failcnt 0
[Wed May 28 23:55:16 2025] kmem: usage 0kB, limit 9007199254740988kB, failcnt 0
[Wed May 28 23:55:16 2025] Memory cgroup stats for /docker/78d543660f71a779c906e792664dd8fb1910e0a108a8974f46bf68f4a1e85de9: cache:1020KB rss:6290436KB rss_huge:0KB mapped_file:4KB swap:0KB inactive_anon:4KB active_anon:6290436KB inactive_file:580KB active_file:408KB unevictable:0KB
[Wed May 28 23:55:16 2025] [ pid ]   uid  tgid total_vm      rss nr_ptes swapents oom_score_adj name
[Wed May 28 23:55:16 2025] [ 8682]     0  8682     1082      394       7        0             0 bash
[Wed May 28 23:55:16 2025] [ 8714]     0  8714  4072191  1569923    4137        0             0 python
[Wed May 28 23:55:16 2025] Memory cgroup out of memory: Kill process 10599 (python) score 1000 or sacrifice child
[Wed May 28 23:55:16 2025] Killed process 8714 (python), UID 0, total-vm:16288764kB, anon-rss:6271900kB, file-rss:7988kB, shmem-rss:4kB

💥 整体结论:

容器 /docker/78d543... 中的一个 python 进程占用了大量内存,超出了限制(6GB),触发了 OOM 杀手机制,最终被系统强制终止。

限制一方面是docker-compose limit or system memory limit


📜 日志逐行解析:

关键系统信息:

[Wed May 28 23:55:16 2025] Hardware name: Alibaba Cloud Alibaba Cloud ECS, BIOS 2221b89 04/01/2014

这台机器是运行在阿里云上的虚拟机(ECS)。


调用栈(Call Trace):

Call Trace:
[<...>] dump_stack
[<...>] dump_header
...

这些是内核触发 OOM 时输出的调用堆栈信息,供开发者排查,正常用户可略过。


容器内存超限:

Task in /docker/78d543660f71... killed as a result of limit of /docker/78d543660f71...

这说明某个容器的进程因为超过内存限制被终止


内存使用情况:

memory: usage 6291456kB, limit 6291456kB, failcnt 1109137
  • usage: 当前使用内存是 6GB(6291456KB)
  • limit: 容器设置的内存上限也是 6GB
  • failcnt: 有 1109137 次尝试使用内存失败(已达上限)
memory+swap: usage 6291456kB, limit 12582912kB
  • 启用了 swap,总限制为 12GB,但实际 swap 并没有用上(见下)。
swap:0KB

被杀进程前的状态:

[ 8714]     0  8714  4072191  1569923 ...

这个 python 进程(PID 8714):

  • total_vm: 虚拟内存空间大约是 16GB(4072191 页 * 4KB)
  • rss: 实际驻留内存是 ~6GB(1569923 页)

杀进程:

Memory cgroup out of memory: Kill process 10599 (python) score 1000 or sacrifice child
Killed process 8714 (python), UID 0, total-vm:16288764kB, anon-rss:6271900kB
  • OOM Killer 选择了 python 进程(PID 8714)进行终止
  • 原因是其 oom_score 高达 1000(最高优先级被杀)
  • 实际占用了约 6GB 匿名页内存

🛠 建议与解决方案:

1. 增加容器内存限制

如果进程是正常业务逻辑(如训练模型、处理大数据),建议将容器内存限制调大:

1
docker run -m 8g ...

或在 Docker Compose / Kubernetes 配置中设置更高的内存限制。


2. 优化 Python 应用内存占用

  • 检查是否有内存泄漏(使用 tracemalloc, objgraph 等工具)
  • 分批处理数据,避免一次加载过多数据
  • 释放不再使用的对象,强制 gc.collect()(如果合理)

3. 使用 cgroupssystemd 分析/监控

也可以用 systemd-cgtopcat /sys/fs/cgroup/... 跟踪各个 cgroup 的内存使用情况。