Linux 有一個保護機制,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