Linux 的 Out-of-Memory (OOM) Killer

同事在 Linux 服务器上遇到点小问题,我也上去折腾半天。这还是第一次注意到 Linux 这个多年来就存在的特性:OOM Killer 。说白了 OOM Killer 就是一层保护机制,用于避免 Linux 在内存不足的时候不至于出太严重的问题,把无关紧要的进程杀掉,有些壮士断腕的意思。

先要学习点老知识,在 32 位CPU 架构下寻址是有限制的。Linux 内核定义了三个区域:

# DMA: 0x00000000 -  0x00999999 (0 - 16 MB) 
# LowMem: 0x01000000 - 0x037999999 (16 - 896 MB) - size: 880MB
# HighMem: 0x038000000 - <硬件特定>

LowMem 区 (也叫 NORMAL ZONE ) 一共 880 MB,而且不能改变(除非用 hugemem 内核)。对于高负载的系统,就可能因为 LowMem 利用不好而引发 OOM Killer 。一个可能原因是 LowFree 太少了,另外一个原因是 LowMem 里都是碎片,请求不到连续的内存区域【根据我遇到的一个案例,一个猜想是 有些应用一次性请求比较大的内存,恰恰又是 880M 之内的,空闲的(LowFree)不够大,就会触发 OOM Killer 出来干活】。检查当前 LowFree 的值:

# cat /proc/meminfo |grep LowFree 

检查LowMem内存碎片:

# cat /proc/buddyinfo

上面这条命令要在 2.6 Kernel 环境下有效。据说使用 SysRq 的方式更好,不过 Hang 的时候再用吧。参见 Metalink Note:228203.1 。

根据一些文档描述,OOM Killer 在 2.4 与 2.6 上表现是不一样的。2.4 的版本中是把新进来(新申请内存)的进程杀掉。而 2.6 上是杀掉占用内存最厉害的进程(这是很危险的,很容易导致系统应用瘫痪)。

对于 RHEL 4 ,新增了一个参数: vm.lower_zone_protection 。这个参数默认的单位为 MB,默认 0 的时候,LowMem 为 16MB。建议设置 vm.lower_zone_protection = 200 甚至更大以避免 LowMem 区域的碎片,是绝对能解决这个问题的(这参数就是解决这个问题出来的)。

而对于 RHEL 3 (Kernel 2.4) 似乎没什么好办法,一个是用 Hugemem 内核(天知道会不会引入新的毛病),一个是升级到 2.4.21-47 并且使用新的核心参数 vm.vm-defragment 控制碎片的数量。再就是使用 RHEL 4 (Kernel 2.6),这又绕回去了。说白了,如果遇到 OOM Killer ,基本上是低版本 Kernel 设计上有点缺陷。

其它,如果去查询 RedHat 的 Bug 库,会发现不少 Kernel 版本也有 Bug 的。尤其在使用 NFS 的场景。

Tip: OOM Killer 的关闭与激活方式:

# echo "0" > /proc/sys/vm/oom-kill 
# echo "1" > /proc/sys/vm/oom-kill

更多参考信息:

EOF

头疼欲裂,零散记录点东西,备查。


11 thoughts on “Linux 的 Out-of-Memory (OOM) Killer

  1. jametong

    我之前是用过升级到hugemem的内核版本解决这个问题的,,系统之后稳定的运行了2年没有出问题吧..
    你们倒是也可以试试..
    我升级之后使用的版本为..
    2.4.21-32.0.1.ELhugemem #1

    Reply
  2. forcey

    我们用的32位系统一直存在这个问题,880M的限制是为4G以下内存设计的,如果物理内存大于4G并打开PAE的话,LowMem很容易爆掉。如果内核保护得好没有爆掉的话,也会有一大片物理内存利用不上。
    升级到64位系统就解决了这个问题,因为64位系统下所有的内存都是LowMem。

    Reply
  3. Fenng

    @forcey
    我这边最后对链接进来的进程数做了控制。“避免”了问题的再次出现。长期来看,还是找个机会升级到 64 位机器上。

    Reply
  4. Zhuang@FUN

    当年,上学时,我们老师就在给我们讲,做我们这一行的(IT),身体状况就没一个完好的,都是处于亚健康状态,,,,,看来又多了一个,呵呵!~~
    哥们可要注意身体哟!!

    Reply
  5. whoami

    光说这个实在太少. OOM 问题和大 tmpfs(用多了内存可能会把无辜的 X 干掉), memory split 问题, 还有曾经的 32bit 1G lowmem patch(不过现在应该没人用了, 作者居然是 Con Kolivas :( )

    Reply
  6. show user

    这个问题以前听基盘的朋友谈起过,说在redhat4上还存在,在redhat5上就修复了。看了你写的发现还不是那样的问题。
    这个出现过Oracle进程被杀掉的情况。比较可怕。

    Reply
  7. kissingwolf

    03年的时候在做imu项目的时候出过这样的问题,服务程序有溢出,最夸张的一次是将sshd kill了,导致无法远程登录!

    Reply
  8. bulletming

    我这有台Slackware,非常重要的Mysql DB,上边也跑了应用程序,应用把内存和Swap吃光了,然后,mysql就自动重启了。dmesg下边又看到Free Swap为0,和oom-killer的字样
    [60083042.176000] Swap cache: add 168883313, delete 168885711, find 92724386/111577334, race 32+7194
    [60083042.176000] Free swap = 0kB
    [60083042.176000] Total swap = 2048152kB
    [60083042.176000] Free swap: 0kB
    [60083042.192000] 1163263 pages of RAM
    [60083042.192000] 933887 pages of HIGHMEM
    [60083042.192000] 141947 reserved pages
    [60083042.192000] 680 pages shared
    [60083042.192000] 0 pages swap cached
    [60083042.192000] 0 pages dirty
    [60083042.192000] 0 pages writeback
    [60083042.192000] 786656 pages mapped
    [60083042.192000] 4073 pages slab
    [60083042.192000] 3274 pages pagetables
    [60083042.192000] oom-killer: gfp_mask=0x201d2, order=0
    [60083042.192000] [] out_of_memory+0x2b/0xa9
    [60083042.192000] [] __alloc_pages+0x1da/0x263
    [60083042.192000] [] __do_page_cache_readahead+0xc1/0x135
    [60083042.192000] [] filemap_nopage+0x149/0x2d5
    [60083042.192000] [] do_no_page+0x93/0x2a2
    [60083042.192000] [] dput+0x1b/0x119
    [60083042.192000] [] __handle_mm_fault+0x147/0x253
    [60083042.192000] [] do_page_fault+0x189/0x55f
    [60083042.192000] [] sys_waitpid+0x13/0x17
    [60083042.192000] [] do_page_fault+0x0/0x55f
    [60083042.192000] [] error_code+0x4f/0x54

    Reply
  9. Fenng

    @bulletming
    第一感觉可能是你的数据库连接开的太多了. 或许是什么突发的因素导致的
    先检查一下吧

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *