写点什么

Linux OOM Killer

发布于: 2021 年 04 月 21 日
Linux OOM Killer

今天介绍一个跟公众号名字很相关的 Linux 内存管理机制。

概念

在软件故障中,Out-Of-Memory(OOM,系统可用内存不足)是最古老的故障之一,并且一直延续至今。


在早期的计算机系统中,内存小到以 kb 为单位,那时的程序员要精细的计算每一条指令的内存使用量,犹如在钢丝绳上表演杂技,稍有不慎就会出现内存不足导致软件或操作系统崩溃,但是即使限制那么苛刻,依然产生了许多伟大的软件,这也是这个公众号的名字由来。


即使今天的家用计算机内存已经至少 8G 起步,操作系统上运行的软件也会遇见 OOM 错误,Linux 为了避免系统内存不足导致整个系统不可用,建立了一套 OOM 管理机制。


Linux 的OOM管理机制会检测可用内存,在内存不足故障发生时选择性的杀死一个或者几个进程以释放内存,而执行这一任务的进程就被称作 Linux Out-Of-Memory(OOM) Killer。


为什么要了解 OOM Killer

那么 Linux 的这一机制对我们有什么影响呢?


因为 OOM Killer 选择杀死哪个进程有不确定性。


在服务器上运行着我们为客户提供服务的进程、监控系统情况的进程、数据库进程等等,通常这些进程的内存占用都相对较大,容易被 OOM Killer 选中。


如果杀死的是客户服务进程或者数据库进程,轻则服务失败降低用户体验,重则丢失数据引起严重的生产事故。


如果杀死的是监控进程,可能造成服务器异常下线,或者无法及时重启等问题。


所以我们需要了解 OOM Killer 的运行机制,然后根据生产服务的情况进行合适的配置,以避免关键进程被杀死带来的损失。

OOM Killer 的机制

Linux 的 OOM 管理机制可以大致分为“检查可用内存-判定 OOM 状态-选择牺牲者进程-杀死牺牲者”四个步骤。

检查可用内存

当程序申请操作系统分配内存时,需要的内存数量会被传递给vm_enough_memory(),除非系统管理员设置了内存过载使用,否则 Linux 会检查可用内存是否充足。


Linux 检查可用内存时,除了当前可以直接使用的free pages内存,还会检查page cache等容易被回收的内存和 swap 交换区的可用空间。


如果这些内存空间加起来能够满足申请分配的数量,Linux 会执行回收并分配内存的动作,不会触发 OOM 处理。

判定 OOM 状态

当系统内存不足,并且向磁盘交换并回收旧页帧(page frames)也无法释放足够的内存时,Linux 会调用out_of_memory()来决策是否要杀死进程。


因为有可能系统只是极短时间的内存不足,等某个 IO 操作完成或者内存换页后就缓解了,所以为了避免误杀进程,在真正杀死进程之前,需要根据一些条件判定是否进入 OOM 状态:


  • 是否有足够的交换空间,如果有,不进入 OOM 状态

  • 是否距离上一次内存分配失败已经超过 5 秒,如果是,不进入 OOM 状态

  • 是否 OOM 检查一秒内未通过次数大于一次,如果否,不进入 OOM 状态

  • 是否在最近 5 秒内至少 10 次内存分配错误,如果否,不进入 OOM 状态

  • 是否 5 秒内已经杀死过一个进程,如果是,不进入 OOM 状态


当前 Linux 内核的规则不一定跟上面完全一样,但是我们可以看出 Linux 会尽力避免频繁的进入 OOM 状态。


所有这些检查都通过之后,就会进入下一步,选择牺牲者进程。

选择牺牲者进程

到了这一阶段,OOM Killer 会从一众程序中按照一定规则计算和选取一个进程杀死并释放内存,以保证系统能够继续运行。选择进程时会遵循如下原则


  • 尽量选择内存占用较多的进程(通常容易命中我们的服务进程)

  • 尽量通过杀死最少的进程来达到目标

  • 尽量不杀死系统和内核运行需要的进程

  • 如果有进程处于SIGKILL或者退出动作中,优先选择以加快内存释放


OOM Killer 通过一套尽心设计的算法计算每个进程的oom_score,按照分数高低选择应该杀死哪个进程。


具体进程的oom_score可以通过命令cat /proc/[pid]/oom_score来查看。


在我的 ubuntu 上,系统进程的oom_score通常是 0,chrome 中内存占用较大页面进程在 300 左右。

杀死牺牲者

选出牺牲者进程后,OOM Killer 会发送``信号杀死牺牲者,即使这个程序本身没有任何问题。


如果内存依然不足,OOM Killer 会重复上面的步骤,继续选择并杀死新的进程,直到释放足够的内存位置,颇有为了拯救世界宁愿杀尽天下人的冷血范。

查看OOM Killer的运行情况

可以通过dmesg命令查看 OOM Killer 的日志记录


sudo dmesg | grep -i “killed process”
复制代码


在不同的发行版也可以查看以下日志


#CentOSgrep -i "out of memory" /var/log/messages
#Debian / Ubuntugrep -i "out of memory" /var/log/kern.log
复制代码

如何控制OOM Killer

我们可以通过以下方法避免 OOM Killer 杀死指定进程。


  • 调整进程的oom_socre

  • 可以向/proc/[pid]/oom_score_adj文件中写入一个负数(例如-1000)来避免进程被选中(oom_adj已经废弃),

  • 为了使系统重启后调整仍然生效,可以在systemdservice unit中写入如下配置


    [Service]    OOMScoreAdjust=-1000
复制代码


  • 关闭 OOM Killer

  • 通过命令sudo -s sysctl -w vm.oom-kill = 0可以关闭 OOM Killer.

  • 通过命令echo vm.oom-kill = 0 >>/etc/sysctl.conf写入配置文件可以使重启后也生效.

  • 但是强烈建议不要关闭 OOM Killer,可能导致系统出现不可预知的异常

  • 配置overcommit_memory内核参数


    sudo sysctl vm.overcommit_memory=2    echo "vm.overcommit_memory=2" >> /etc/sysctl.conf
复制代码


`overcommit_memory`有三个取值:
0 - 操作系统自行决定进程是否过载使用内存,通常这是默认值
1 - 强制过载使用内存,这样配置会有导致内核进程内存不足的风险,适用于某些内存必须分配成功的科学计算场景
2 - 不允许过载使用内存,意味着系统分配的内存不会超过总内存乘以`overcmmit_ratio`(`/proc/sys/vm/overcommit_ratio`,默认50%),这是最安全的配置。
复制代码


  • 配置panic_on_oom内核参数

  • echo 1 > /proc/sys/vm/panic_on_oom

  • panic_on_oom内核参数设置为 1 可以让系统在内存不足时抛出内核错误(kernel panic),这通常也不是我们希望的。

  • 增加内存😀

  • 可能有点废话,不过如果经常内存不足,物理手段有时比软件优化来得快速有效。

  • 降低软件的内存消耗,修复内存泄漏问题。

  • 大部分场景下,软件系统自身错误的内存使用方式和 Bug 是内存不足的主要元凶,例如在数据库查询中不限制查询出来的记录数量等等


访问作者技术博客浏览更多文章



发布于: 2021 年 04 月 21 日阅读数: 20
用户头像

吃货开发者的探索 2014.08.16 加入

金融科技架构师

评论

发布
暂无评论
Linux OOM Killer