freeとvmstatの両方でfreeをチェックする。両方の出力でfreeの定義が違っている様子。freeコマンドMem項目のfreeは空きメモリ、bufferはバッファキャッシュ、chachedはページキャッシュ、空きメモリとバッファキャッシュとページキャッシュの和が-/+ buffers/cacheのfree。Linuxは起動中に空きメモリから割り当てたメモリをメモリ使用後にすぐに開放するのではなく、キャッシュ(バッファキャッシュ、ページキャッシュ)に蓄えておき、再利用できるようにしている。キャッシュは「効率化」のためのもので、空きメモリを越えるサイズのメモリアロケーションが行われた場合には不足分をキャッシュから割り当てられる。つまり、アプリケーションがアロケーション可能なメモリサイズは空きメモリ+バッファキャッシュ+ページキャッシュ。これを表しているのがfreeの-/+ buffers/cacheのfree。計算が面倒でなければ、vmstatのfreeとbuffとcacheを足し算すればよい。
$ free total used free shared buffers cached Mem: 1035792 984852 50940 0 256344 375956 -/+ buffers/cache: 352552 683240 Swap: 489940 0 489940 $ vmstat procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu---- r b swpd free buff cache si so bi bo in cs us sy id wa 5 0 0 51292 256352 375956 0 0 0 0 1 0 97 0 3 0
cronに仕込んで1時間に1回の定点観測。両方のコマンドにはdelayを指定してポーリングする機能がある。vmstatに関してはメモリに関する情報が瞬間のモノだということなので自前のポーリングでもcronでも変わらないはず。freeについては不明。
$ crontab -l # m h dom mon dow command 0 * * * * vmstat | tail -n 1 >> vmstat.dat 0 * * * * free | tail -n 3 | sed 's/^.*:\s*//' | tr '\n' ' ' | sed 's/$/\n/' >> free.dat
出来たログファイルは以下のような感じ。vmstatの方はヘッダー部分を削除したもの。freeの方は項目名を削除して数値だけを1行にまとめたもの。
$ tail vmstat.dat tail vmstat.dat 5 0 0 53068 256288 375928 0 0 0 0 1 0 97 0 3 0 9 0 0 52240 256296 375936 0 0 0 0 1 0 97 0 3 0 9 0 0 53396 256300 375936 0 0 0 0 1 0 97 0 3 0 7 0 0 53288 256300 375944 0 0 0 0 1 0 97 0 3 0 10 0 0 52972 256308 375944 0 0 0 0 1 0 97 0 3 0 7 0 0 52608 256312 375948 0 0 0 0 1 0 97 0 3 0 6 2 0 52120 256312 375948 0 0 0 0 1 0 97 0 3 0 11 1 0 52464 256312 375944 0 0 0 0 1 0 97 0 3 0 7 0 0 52744 256312 375944 0 0 0 0 1 0 97 0 3 0 8 0 0 52072 256312 375944 0 0 0 0 1 0 97 0 3 0 $ tail free.dat 1035792 982624 53168 0 256284 375932 350408 685384 489940 0 489940 1035792 983552 52240 0 256296 375936 351320 684472 489940 0 489940 1035792 982396 53396 0 256300 375936 350160 685632 489940 0 489940 1035792 982504 53288 0 256300 375944 350260 685532 489940 0 489940 1035792 982620 53172 0 256308 375944 350368 685424 489940 0 489940 1035792 982584 53208 0 256312 375948 350324 685468 489940 0 489940 1035792 983472 52320 0 256312 375948 351212 684580 489940 0 489940 1035792 982640 53152 0 256312 375944 350384 685408 489940 0 489940 1035792 982948 52844 0 256312 375944 350692 685100 489940 0 489940 1035792 983220 52572 0 256312 375944 350964 684828 489940 0 489940
得られたログファイルをプロットしてみる。
$ cat vmstat.plot #!/usr/bin/gnuplot set term svg set output "vmstat.svg" set xlabel "times [hour]" set ylabel "(free, buff, cache) bytes [MB]" set y2label "(free+buff+cache) bytes [MB]" set y2range [:] set ytics nomirror set y2tics set key left bottom plot "vmstat.dat" using 0:($4/1000) title "free",\ '' using 0:($5/1000) title "buff",\ '' using 0:($6/1000) title "cache",\ '' using 0:(($6+$5+$4)/1000) axis x1y2 title "free+cache+buff" $ gnuplot < vmstat.plt
vmstatのログをプロットした結果が以下。空きメモリだけに注目すると、50MBでメモリ不足かもしれないと思ってしまうかもしれないけれど、アロケーション可能なメモリに注目すると、680MBでメモリは十分に余っていることがわかる。
このままでは、vmstatのメモリに関する情報もディスクアクセスに関する情報も瞬間の情報になるので、あまりよろしくない。vmstatにはメモリに関する情報以外をある時間間隔の平均値として出力するオプションがあるので、それを使う。ただし、これを用いた場合、vmstatが終了しなくなるので、cronに書いておくと呼び出された回数だけ、プロセスが起動してしまう。これを防ぐために、二重起動を制御する部分を加えたシェルスクリプトにして、これをcronから呼び出すようにする。cronを使って1時間に1回0分のときに起動チェック。起動しているかしていないかの基準は/tmp以下につくったシンボリックリンク(シンボリックリンクってアトミックだっけ?)。起動していた場合は何もせずにシェルスクリプト終了。起動していない場合は目的のvmstatを走らせて終了待ち状態に移行。cronから起動された際には子プロセスの終了を待たずに起動したシェルを正常終了させたいので、起動したシェルの標準出力とエラー出力を閉じておくためのおまじない"> /dev/null 2>&1 &"を付け加えておく。
$ cat vmstat.sh sem="/tmp/checkvmstat" ln -s /dummy $sem || exit trap "rm $sem; exit" 2 3 15 nohup nice vmstat -n 3600 >> vmstat_.dat rm "$sem" exit $ crontab -l # m h dom mon dow command #0 * * * * vmstat | tail -n 1 >> vmstat.dat 0 * * * * free | tail -n 3 | sed 's/^.*:\s*//' | tr '\n' ' ' | sed 's/$/\n/' >> free.dat 0 * * * * sh ~/vmstat.sh > /dev/null 2>&1 &