Linux OOM Killer 是什么?程序为什么突然被杀?
1. 前言
线上服务有时会突然消失。
你没有手动 kill,程序也没有正常退出,但进程就是没了。
查看日志后可能看到:
Out of memory: Killed process 1234 (java)
这通常就是 Linux OOM Killer 触发了。
本文讲解:
- OOM 是什么;
- OOM Killer 为什么会杀进程;
- 如何查看 OOM 日志;
- Linux 怎么选择杀哪个进程;
- 如何避免程序被 OOM;
- Docker/Kubernetes 中 OOM 有什么特点。
2. OOM 是什么
OOM 全称:
Out Of Memory
意思是内存不足。
当系统内存严重不足,无法满足新的内存分配请求时,Linux 内核可能会触发 OOM Killer。
OOM Killer 的作用是:
选择一个或多个进程杀掉,释放内存,避免整个系统崩溃。
3. OOM Killer 为什么要杀进程
如果系统内存完全耗尽,可能导致:
- 新进程无法启动;
- 现有进程无法分配内存;
- 系统响应变慢;
- SSH 无法登录;
- 内核关键路径受影响。
为了自保,内核会杀掉某个"代价较高"的进程,释放内存。
这就是 OOM Killer。
4. 如何查看 OOM 日志
使用 dmesg:
dmesg | grep -i "out of memory"
查看被杀进程:
dmesg | grep -i "killed process"
使用 journalctl:
journalctl -k | grep -i "killed process"
或:
journalctl -k | grep -i "oom"
示例:
Out of memory: Killed process 1234 (java) total-vm:4096000kB, anon-rss:2048000kB
说明 PID 1234 的 java 进程被杀。
5. OOM 日志怎么看
示例字段:
Killed process 1234 (java) total-vm:4096000kB, anon-rss:2048000kB, file-rss:0kB
含义:
| 字段 | 含义 |
|---|---|
| PID | 被杀进程 ID |
| 进程名 | 例如 java、mysqld |
total-vm |
虚拟内存 |
anon-rss |
匿名常驻内存 |
file-rss |
文件映射内存 |
oom_score |
OOM 评分 |
重点看:
哪个进程被杀
当时内存大概占用多少
是否频繁出现
6. Linux 怎么选择杀哪个进程
Linux 会给进程计算 OOM 分数。
查看某进程分数:
cat /proc/PID/oom_score
查看调整值:
cat /proc/PID/oom_score_adj
oom_score 越高,越容易被杀。
oom_score_adj 范围:
-1000 到 1000
| 值 | 含义 |
|---|---|
-1000 |
尽量不被 OOM 杀 |
0 |
默认 |
1000 |
更容易被杀 |
不建议随便把业务进程设置为 -1000。
如果所有进程都不让杀,系统可能更危险。
7. OOM 前的典型现象
常见表现:
free -h中 available 很低;- Swap 使用很多;
vmstat中 si/so 持续不为 0;- 应用内存持续上涨;
- 系统响应变慢;
- 日志中出现 OOM;
- 进程无异常日志但突然退出。
查看:
free -h
vmstat 1
ps aux --sort=-%mem | head
8. 常见导致 OOM 的原因
8.1 内存泄漏
进程 RSS 持续增长,最终被杀。
查看趋势:
ps -p PID -o pid,%mem,rss,cmd
持续观察:
pidstat -r -p PID 1
8.2 JVM 参数过大
例如服务器只有 2GB 内存,却设置:
-Xmx3g
很容易 OOM。
8.3 MySQL/Redis 配置过大
Redis 如果没有设置 maxmemory,可能无限占用内存。
MySQL buffer pool、连接数配置过大,也会造成内存压力。
8.4 突发流量
大量请求导致:
- 线程增多;
- 队列堆积;
- 缓存增长;
- 对象创建增加。
8.5 容器内存限制
Docker 或 Kubernetes 设置了内存限制。
容器超过限制会被杀,即使宿主机还有内存。
9. Docker 中的 OOM
查看容器是否 OOM:
docker inspect 容器名 | grep -i oom
或者:
docker inspect --format='{{.State.OOMKilled}}' 容器名
如果输出:
true
说明容器曾因 OOM 被杀。
运行容器时可以设置内存限制:
docker run -d --memory=512m --name myapp myapp:1.0
如果应用超过 512MB,可能被 OOM kill。
10. 如何避免 OOM
10.1 监控内存
定期观察:
free -h
ps aux --sort=-%mem | head
生产环境需要监控:
- 内存使用率;
- available;
- Swap;
- 进程 RSS;
- OOM 日志。
10.2 合理配置应用内存
Java:
-Xms512m -Xmx512m
Redis:
maxmemory 1gb
maxmemory-policy allkeys-lru
MySQL:
innodb_buffer_pool_size
max_connections
10.3 限制容器资源
docker run --memory=1g --cpus=1 myapp
避免单个容器吃光宿主机资源。
10.4 增加 Swap
Swap 不是根本解决方案,但可以缓冲突发内存压力。
查看:
swapon --show
11. OOM 排查流程
dmesg | grep -i "killed process"
journalctl -k | grep -i oom
free -h
vmstat 1
ps aux --sort=-%mem | head
cat /proc/PID/oom_score
流程:
确认是否 OOM
↓
找到被杀进程
↓
查看当时日志
↓
检查系统内存和 Swap
↓
分析进程内存趋势
↓
检查应用配置
↓
判断是否需要扩容或修复内存泄漏
12. 小结
OOM Killer 是 Linux 内核在内存严重不足时的自救机制。
关键点:
OOM 不是普通应用异常退出
它是内核主动杀进程
dmesg/journalctl 可以查证据
oom_score 越高越容易被杀
容器也可能因内存限制被 OOM
常用命令:
dmesg | grep -i "killed process"
journalctl -k | grep -i oom
free -h
vmstat 1
ps aux --sort=-%mem | head
docker inspect --format='{{.State.OOMKilled}}' 容器名
避免 OOM 的核心是:
监控内存
限制单进程内存
合理配置 JVM/MySQL/Redis
设置容器资源限制
排查内存泄漏
必要时扩容
如果程序"突然没了",第一时间就应该查 OOM 日志。