天天看點

Out of memory

環境:

Ubuntu Server 12.04  i686

問題描述:

24G記憶體,空閑的有20G左右。但是核心老是報這個,動不動就殺程式 

Jul  6 13:12:44 00098 kernel: [3112325.883069] Out of memory: Kill process 2249 (nginx) score 1 or sacrifice child 

Jul  6 13:12:44 00098 kernel: [3112325.922795] Killed process 2831 (nginx) total-vm:21772kB, anon-rss:11048kB, file-rss:916kB 

Jul  6 12:43:18 00098 kernel: [3110562.214498] snmpd invoked oom-killer: gfp_mask=0x840d0, order=0, oom_adj=0, oom_score_adj=0 

Jul  6 12:43:18 00098 kernel: [3110562.214502] snmpd cpuset=/ mems_allowed=0 

Jul  6 12:49:57 00098 kernel: [3110960.995962] Out of memory: Kill process 1858 (mysqld) score 1 or sacrifice child 

Jul  6 12:49:57 00098 kernel: [3110961.032675] Killed process 1858 (mysqld) total-vm:140652kB, anon-rss:15492kB, file-rss:6100kB 

Jul  6 12:49:57 00098 kernel: [3110961.103870] init: mysql main process (1858) killed by KILL signal 

Jul  6 12:49:57 00098 kernel: [3110961.103899] init: mysql main process ended, respawning 

 真的是很郁悶啊,搭建了一個Cacti,系統上剛好有Nginx,是以就用了Nginx,要提供php的支援,還必須安裝php5-fpm,安裝完成後,登陸上Cacti,過一會兒一重新整理,就挂掉了,剛開始還以為是Nginx挂掉了,就沒在意,過一會兒,監控報警說Nginx挂掉了,看了下Nginx的日志,沒發現異常,今天又發現MySQL挂了,這下蛋疼了,怎麼程式動不動就挂呢!仔細分析了一下日志,發現核心報了以上内容,OOM-KILLER這個東西,動不動就殺程式,但是記憶體并沒有滿,空的很。

然後網上找了下資料,32位的系統,如果Low-memory耗盡,就會導緻這個問題的出現。看了一下Low-memory,确實很少!

通常,在大記憶體(6Gb+)伺服器上,out of memory killer (oom-killer)也會殺死程序。在很多case中,人們都困惑地報告說還有剩餘記憶體的情況下,為何oom-killer還會殺死程序?現象是在 /var/log/messages 日志中,有如下資訊:

  Out of Memory: Killed process [PID] [process name].

在我自己的case中,我在VMware中更新了各個RHEL3到RHEL4,有1個16Gb記憶體的伺服器,還是會被oom-killer殺死程序。不用說,這非常令人沮喪。

事實證明,這個問題的原因是low memory耗盡。引用Tom的話“核心使用low memory來跟蹤所有的記憶體配置設定,這樣的話一個16GB記憶體的系統比一個4GB記憶體的系統,需要消耗更多的low memory,可能有4倍之多。這種額外的壓力從你剛啟動系統那一刻就開始存在了,因為核心結構必須為潛在的跟蹤四倍多的記憶體配置設定而調整大小

說白了 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 裡都是碎片,請求不到連續的記憶體區域

有兩種方法檢視 low memory 和 high memory 的狀态:

# egrep 'High|Low' /proc/meminfo 

HighTotal:     5111780 kB 

HighFree:         1172 kB 

LowTotal:       795688 kB 

LowFree:         16788 kB 

# free -lm 

             total       used       free     shared    buffers     cached 

Mem:          5769       5751         17          0          8       5267 

Low:           777        760         16          0          0          0 

High:         4991       4990          1          0          0          0 

-/+ buffers/cache:        475       5293 

Swap:         4773          0       4773 

當low memory耗盡,不管high memory剩餘多少,oom-killer都開始殺死程序,以保持系統的正常運轉。

有兩種方法可以解決這個問題

1、如果可能,請更新到64位系統。

這是最好的解決辦法,因為所有的記憶體都将成為low memory。如果你在這種情況下耗盡了low memory,那就真的是out of memory了。

2、如果受限于必須使用32位系統,最好的解決辦法是使用hugemem核心。

這種核心以不同的方式分割low/high memory,而且在大多數情況下會提供足夠多的low memory到high memory的映射。在大多數案例中,這是一個很簡單的修複方法:安裝hugemem kernel RPM包,然後重新開機即可。

如果運作hugemem核心也不可能,你可以嘗試将/proc/sys/vm/lower_zone_protection 的值設定為250甚至更多。這将讓核心願意保護low memory,進而在配置設定記憶體時多考慮從high memory配置設定。據我所知,此選項從2.6.x核心才開始可用。必要的是,您可能需要通過一些實驗來找到您系統環境中最适合的值。可以使用下面方法快速的設定和檢查改值:

# cat /proc/sys/vm/lower_zone_protection 

# echo "250" > /proc/sys/vm/lower_zone_protection 

在 /etc/sysctl.conf 中加入設定,以便啟動就生效:

  vm.lower_zone_protection = 250

作為最後的努力,你可以關閉oom-killer。這個選項可以導緻系統挂起,是以請小心使用(風險自負)!

檢視目前oom-killer的狀态:

# cat /proc/sys/vm/oom-kill 

關閉/打開oom-killer:

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

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

當程序該被oom-killer殺死卻沒有被殺死時,相關資訊會記錄到 /var/log/messages:

"Would have oom-killed but /proc/sys/vm/oom-kill is disabled"

本文轉自 gm100861 51CTO部落格,原文連結:

http://blog.51cto.com/gm100861/922664