OOM-killer(Out of Memory Killer)引发业务系统故障
什么是 OOM Killer
了解OOM-killer是什么之前,先了解下Linux的内存超量分配。
什么是内存OverCommit
Linux下允许程序申请比系统可用内存更多的内存,这个特性叫Overcommit。这样做是出于优化系统考虑,因为不是所有的程序申请了内存就立刻使用的,当你使用的时候说不定系统已经回收了一些资源了。不幸的是,当你用到这个Overcommit给你的内存的时候,系统还没有资源的话,OOM killer就跳出来了。
参数/proc/sys/vm/overcommit_memory可以控制进程对内存过量使用的应对策略
- 当overcommit_memory=0 允许进程轻微过量使用内存,但对于大量过载请求则不允许,也就是当内存消耗过大就是触发OOM killer。
- 当overcommit_memory=1 永远允许进程overcommit,不会触发OOM killer。
- 当overcommit_memory=2 永远禁止overcommit,不会触发OOM killer。
OOM-Killer
OOM Killer(Out Of Memory Killer)是 Linux 内核在系统内存耗尽时启用的一种保护机制。
当系统物理内存和交换空间完全耗尽,且无法满足新的内存分配请求时,内核会启动 OOM Killer 来终止一些进程以释放内存,防止系统崩溃。
OOM的工作机制
当系统内存不足且无法通过内存回收机制(如交换空间或页面回收)满足需求时,OOM Killer 会被触发。
通常oom_killer的触发流程是:进程A想要分配物理内存(通常是当进程真正去读写一块内核已经“分配”给它的内存)->触发缺页异常->内核去分配物理内存->物理内存不够了,触发OOM。
它会根据特定的算法为每个进程打分,通常考虑以下因素:
- 内存占用量:进程使用的内存越多,得分越高。
- 进程重要性:系统关键进程(如内核线程)得分较低,不易被终止。
- 进程运行时间:运行时间较长的进程可能得分较低。
根据这些评分,OOM Killer 会选择得分最高的进程进行终止,以释放内存资源。
触发原因
OOM Killer 主要在以下情况下被触发:
- 内存泄漏:某些进程持续占用内存且未释放,导致系统内存耗尽。
- 内存过度分配:进程请求的内存超过系统可用内存。
- 内存碎片化:尽管总内存充足,但无法找到连续的内存块满足进程需求。
现象
通过系统日志(如/var/log/messages)看到类似下图日志条目:
开始调用oom-killer

oom-killer通过打分kill进程

检查内存使用

相关参数
overcommit_memory
参数/proc/sys/vm/overcommit_memory可以控制进程对内存过量使用的应对策略
- 当overcommit_memory=0 允许进程轻微过量使用内存,但对于大量过载请求则不允许,也就是当内存消耗过大就是触发OOM killer。
- 当overcommit_memory=1 永远允许进程overcommit,不会触发OOM killer。
- 当overcommit_memory=2 永远禁止overcommit,不会触发OOM killer。
panic_on_oom
参数:panic_on_oom: 用来控制当内存不足时该如何做。
查看:cat /proc/sys/vm/panic_on_oom
值为0:内存不足时,启动 OOM killer。
值为1:内存不足时,有可能会触发 kernel panic(系统重启),也有可能启动 OOM killer。
值为2:内存不足时,表示强制触发 kernel panic,内核崩溃GG(系统重启)。
oom_kill_allocating_task
参数:oom_kill_allocating_task: 用来决定触发OOM时先杀掉哪种进程
cat /proc/sys/vm/oom_kill_allocating_task
值为0:会 kill 掉得分最高的进程。
值为非0:会kill 掉当前申请内存而触发OOM的进程。
当然,一些系统进程(如init)或者被用户设置了oom_score_adj的进程等可不是说杀就杀的。
oom_dump_tasks
参数:oom_dump_tasks:用来记录触发OOM时记录哪些日志
cat /proc/sys/vm/oom_dump_tasks
oom_dump_tasks参数可以记录进程标识信息、该进程使用的虚拟内存总量、物理内存、进程的页表信息等。
值为0:关闭打印上述日志。在大型系统中,可能存在上千进程,逐一打印使用内存信息可能会造成性能问题。
值为非0:有三种情况会打印进程内存使用情况。
- 由 OOM 导致 kernel panic 时;
- 没有找到符合条件的进程 kill 时;
- 找到符合条件的进程并 kill 时。
oom_adj、oom_score_adj 和 oom_score
参数:oom_adj、oom_score_adj 和 oom_score:用来控制进程打分(分数越高,就先杀谁)
这三个参数的关联性比较紧密,都和具体的进程相关,位置都是在 /proc/进程PID/ 目录下。
内核会对进程打分(oom_score),主要包括两部分,系统打分和用户打分。系统打分就是根据进程的物理内存消耗量(进程自身的空间、swap空间、页缓存空间);
用户打分就是 oom_score_adj 的值。如果用户指定 oom_score_adj 的值为 -1000,也就是表示禁止 OOM killer 杀死该进程。
用户可以通过调整 oom_score_adj 的值来决定最终 oom_score 的值,oom_score_adj 的取值范围是 -1000~1000,为0时表示用户不调整 oom_score。另外,root进程拥有3%的内存使用特权,因此做最终 oom_score 计算时需要减去这些内存使用量。
oom_adj是一个旧的接口参数,其功能类似oom_score_adj,为了兼容,目前仍然保留这个参数,当操作这个参数的时候,kernel实际上是会换算成oom_score_adj。
如何防止发生OOM-killer
防止 OOM 触发:
- 增加物理内存或交换空间。
- 优化应用程序的内存使用。
- 配置合理的 overcommit_memory 和 overcommit_ratio 参数,避免内存分配过度。对于高可靠性场景(如数据库、内存密集型应用),关闭overcommit_memory(设置为2)
sysctl vm.overcommit_memory=2
echo "vm.overcommit_memory=2" >> /etc/sysctl.conf
合理保护关键进程:
- 使用 oom_score_adj 降低关键进程被杀的可能性(如数据库服务)。
echo -17 > /proc/2592/oom_score_adj
监控内存使用:
- 定期使用工具(如 top, htop, vmstat, 或 sar)监控系统内存状态。
- 配置告警系统,及时检测内存异常。