确认是oom killer所为:直接运行dmesg -t | grep -i "killed process",若输出类似[mon sep 20 14:22:37 2026] killed process 12345 (java) anon-rss:3456780kb,且anon-rss接近物理内存总量,即坐实oom;无输出需检查kernel.dmesg_restrict权限并临时放开。

怎么确认真是OOM Killer干的
别翻应用日志,它根本没机会写。直接查内核环形缓冲区:dmesg -T | grep -i "killed process"。有输出基本坐实——比如出现 [Mon Sep 20 14:22:37 2026] Killed process 12345 (java) total-vm:4567890kB, anon-rss:3456780kB 这种行,就不用再往下猜了。
常见坑:dmesg -T 在 CentOS 6 或某些加固系统上可能不支持,可改用 dmesg | tail -100 手动找时间戳;若无输出,先检查权限:sudo sysctl kernel.dmesg_restrict,返回 1 就得临时放开:sudo sysctl kernel.dmesg_restrict=0。
怎么看被杀进程到底占了多少真实内存
anon-rss 是关键数字,它代表该进程实际占用的物理内存(不含 page cache、文件映射等),比 total-vm 或 free -h 显示的 “available” 更可信。如果 anon-rss 接近或超过宿主机物理内存总量,说明不是“看着还剩点”,而是真爆了。
- 查当前内存水位:运行
cat /proc/meminfo | grep -E "(MemAvailable|Committed_AS|CommitLimit)",若Committed_AS > CommitLimit,内核已判定虚拟内存承诺过载 - 查 slab 泄漏:运行
slabtop -o,盯dentry、inode_cache、ext4_inode_cache是否异常增长 - 查 cgroup 限额(容器/VM 环境):进入
/sys/fs/cgroup/memory/xxx/,看memory.usage_in_bytes是否逼近memory.limit_in_bytes
为什么杀的是它,而不是那个更占内存的
OOM Killer 不是单纯比 RSS,而是算综合分:oom_score。这个分由 oom_score_adj(手动调权值)和实际内存占用共同决定。root 进程默认 oom_score_adj = -1000(免疫),普通进程默认为 0,Docker 容器常被设为 1000(优先杀)。
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
查某个进程得分:ps -eo pid,comm,oom_score,oom_score_adj --sort=-oom_score | head -10。如果发现你的服务 oom_score 高但 rss 并不突出,大概率是它生命周期短、用户权限低、又被显式调高了 oom_score_adj。
查到是OOM之后,下一步该盯什么
OOM 是结果,不是原因。得顺着被杀进程反推泄漏源头:
- Java 进程:重点看堆外内存——
jmap -histo:live PID看DirectByteBuffer实例数;加-XX:+PrintGCDetails -Xloggc:gc.log分析 GC 日志是否频繁 full gc 且回收无效 - PHP-FPM:开状态页
curl http://127.0.0.1/status?full,看各 worker 的memory_usage是否个别飙升;结合pm.max_requests = 500强制轮转防累积 - Python 进程:用
psutil.Process(PID).memory_info()对比rss和vms,差值大说明 mmap 或 ctypes 分配未释放;检查是否有multiprocessing子进程泄漏或未 join
真正难啃的点往往不在应用层代码,而在内核态资源没释放——比如驱动级内存泄漏、cgroup v1 的 memory accounting 错误、或容器运行时对 memory.kmem.limit_in_bytes 的误配置。这些不会在 ps 或 top 里体现,但会持续抬高 anon-rss。










