メモリを食いまくるプロセスがメモリ使用量に与える影響をtopで追う


暴走してどんどんメモリを食うスクリプトが OS全体のメモリ使用量(CentOS5 ... カーネルは2.6系になる)の動作にどんな影響を与えるのか ってのを見るために以下のようなテストをしてみました。仕組みはだいたい理解してるけど、細かい数値を追ったことはなかったのでやってみました。

  • sshでログインして、topを立ち上げる。プロセスを見張る用意をしておく
  • 別のsshをたちあげて、 Perlワンライナーで以下のようなプロセスを走らせる(このプロセスをtopで見張る)
# 1秒ごとに5MB単位でメモリを食うプロセス
# 数値はお好みで
perl -e "while(1){ sleep 1; push @h  , 1 x 1024 x 1024 x 5 } "


ちなみにtopで見張るときは

  • メモリ使用量でソートされるようにして
    • top起動中に shift + o を押して n を押すと 実メモリ使用量でソートされる
  • 更新時間を短くする
    • top 起動中に d を押して、秒数を指定する。今回は1秒で
    • top -d1 でもいいみたい(追記)
  • ついでに色を付けておく
    • top起動中にB もしくは z を押す / x を押すとソートしているカラムの色だけが反転表示

という設定にしておくと数値が見やすいと思います。自分の設定では画像のようになりました。赤いなぁ



さて以上のような条件で実際に実行してみると Perlのプロセスが1秒ごとに5MBずつメモリを食っていく様子が分かるのですが、注目してみておくべき数値は、Perlのプロセスのメモリ使用率と、メモリ/ スワップ使用量の統計だと思います。1秒ごとに数値が変化するのですが、ただ単純に数値が増えていく というわけではなくて、あっちがふえたりこっちが減ったりとなかなか興味深い動きをします。以下、topのスナップショットを貼っていきます。

( 実際にご自身の環境で試して目で追ってもらった方が分かりやすいと思いますが....あと、メモリの総計を追うだけならvmstatの方がいいですね)

# 初期値
# Perlのメモリ食いプロセスはまだ動いていません

top - 07:58:48 up 7 min,  2 users,  load average: 0.10, 0.21, 0.11
Mem:    255768k total,   122604k used,   133164k free,     7932k buffers
Swap:   524280k total,        0k used,   524280k free,    81424k cached
# Mem: usedが若干増えて、freeが若干減る
#perlのプロセスがソートの上位にあがってくる

top - 07:58:53 up 7 min,  2 users,  load average: 0.09, 0.21, 0.11
Mem:    255768k total,   135536k used,   120232k free,     7992k buffers
Swap:   524280k total,        0k used,   524280k free,    82688k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                      
 1979 root      18   0 14888  12m 1032 S  4.6  4.9   0:00.07 perl  

# Mem: totalが Mem:usedとほぼ同値になった ( Mem: freeがかなり減少 )
# PerlのRES(実メモリ使用量) が 127MB。 %MEMは51.0 
# ここからbuffersとcachedが減少し始める

top - 07:59:17 up 8 min,  3 users,  load average: 0.07, 0.20, 0.10
Mem:    255768k total,   252228k used,     3540k free,     7856k buffers
Swap:   524280k total,        0k used,   524280k free,    79792k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                      
 1979 root      18   0  129m 127m 1032 S  4.5 51.0   0:00.81 perl  
# Mem:usedはほとんど動かない
# buffers/cachedがどんどん減っている

top - 07:59:27 up 8 min,  3 users,  load average: 0.21, 0.22, 0.11
Mem:    255768k total,   252756k used,     3012k free,      348k buffers
Swap:   524280k total,       80k used,   524200k free,    36664k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                      
 1979 root      18   0  179m 177m 1032 S  4.6 71.0   0:01.10 perl  
# cachedが食い尽くされて、Swap: used が増加し始める
# この時点からPerlの VIRT(実メモリ+スワップ)の値がRES(実メモリのサイズ)と大きく差をつけるようになる

top - 07:59:37 up 8 min,  3 users,  load average: 0.28, 0.24, 0.12
Mem:    255768k total,   251672k used,     4096k free,       60k buffers
Swap:   524280k total,    14144k used,   510136k free,     5976k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                      
 1979 root      18   0  219m 207m  580 S  4.4 82.9   0:01.43 perl                                                                                                                                         
# プロセス肥大中 / Swapのusedが大きくなってる

top - 08:01:25 up 10 min,  3 users,  load average: 1.96, 0.66, 0.27
Mem:    255768k total,   248980k used,     6788k free,      404k buffers
Swap:   524280k total,   415600k used,   108680k free,     7540k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                      
 1979 root      18   0  569m 179m  268 R  2.8 71.8   0:03.91 perl  
# スワップのfreeが0に!!!!!
# PerlのVIRT(実メモリ+スワップ) が725MB。
# メモリが枯渇状態MAX

top - 08:02:04 up 11 min,  3 users,  load average: 1.70, 0.70, 0.29
Mem:    255768k total,   251892k used,     3876k free,       68k buffers
Swap:   524280k total,   524280k used,        0k free,     1812k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                      
 1979 root      18   0  725m 232m  276 S  3.4 93.1   0:05.19 perl 
#Swapも食い尽くしてしまうと急にMem: free/Swap:freeの値が増えます。
#Perlのメモリバカ食いプロセスは消えています。
#Perlのワンライナーを起動したsshの画面を見ると「Out of memory!」という文字が出てします。
#これが噂のOOM-Killerですね。と言っても今回初めて見ました。

top - 08:02:05 up 11 min,  3 users,  load average: 1.70, 0.70, 0.29
Mem:    255768k total,    15492k used,   240276k free,      120k buffers
Swap:   524280k total,    22952k used,   501328k free,     3380k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                      
   85 root      10  -5     0    0    0 S  0.6  0.0   0:00.70 kswapd0    
 

プロセスが肥大化してメモリを食いきってしまうとカーネルがOOM Killerなる機構を呼び出して肥大したプロセスをkillする( SIGEMT を送る) ようです。以下、ググってでてきたページから引用して載せておきます。

http://wiki.livedoor.jp/linuxfs/d/OOMkiller

Linux kernelがメモリ不足(swapも含め)に陥ったとき、このOOM Killerが発動し、縦横無尽にプロセスを駆逐していきます。その際、無差別ともとれる残虐な行為から悪名高いメモリ不足解決器 (OOM killer) と揶揄されて今日に至ります。

メモリが枯渇した状態でOOM Killerが呼び出されるので、OOM Killer自体はメモリをほとんど割り当てないような実装になってるって どこかで読んで、なるほどー!と思ったんですけど どこだったか忘れてしまいました。

ちなみにOOM Killerが呼び出された詳細は /var/log/message 以下にログがとられています。


なんとなく思いつきでやったテストでしたが、カーネルがメモリを操る様子が逐一見て取れたので非常にためになりました。OOM Killer が起動するタイミングも確認することが出来たし。( topの更新時間を0.01秒単位で指定するとさらにダイナミックな変化が追えます)
他に見るべきポイントがあったらつっこみ待ちです