Kodama's home / tips.
PC の動作が遅くなる原因は様々な要因が絡み合っているので, 表面に現れた症状だけでは効果的な対策が分からない事もある. 以下では, メモリ−関連にしぼって解説する.
$ free total used free shared buffers cached Mem: 192572 190944 1628 54912 20112 126848 ....略
Linux(っていうか UNIX かな?) では, 各プロセスにメモリを割り振った残りを バッファ(buffer)とキャッシュ(cache)に利用して, ディスク入出力の負荷を減らしている. そのため, free コマンド等で見える残りメモリ−(free)は 1M 程度の 瞬間的な使いまわしに対処する程度しか残っていない事が多い.
$ free total used free shared buffers cached Mem: 192572 190944 1628 54912 20112 126848 -/+ buffers/cache: 43984 148588 <----ここを見る Swap: 96384 0 96384
この例では, 実質的な残りメモリ−は, バッファとキャッシュに転用された分も考慮すると free+buffers+cached で計算できる. 上の例で云うと free+buffers+cached = 1628+20112+126848 = 148588. まだまだ, メモリ−には余裕がある.
free コマンドでは全体のメモリーの使用状況しか分からない. 個々のプロセスのメモリーの使用状況を調べるには top や ps を用いる.
メモリーリークを検出する方法としては以下の様なものがある.
malloc と free の検証が重要となるのは, 長期間動作を続けるようなプログラム(サーバソフトなど)で 小量のメモリーリークが積み重なって動作不良の原因とならないかということだ. ゆっくりしたメモリーリークは, 検出用のツールを使わないと確認が難しい.
短い時間の処理で終了するようなプログラムでは, メモリーリークを放っておいても終了時にシステムに回収されるので気にする必要はない. ...というのを学校の課題提出とか, 顧客に納品するソフトで表だって云うと問題だが, OS をメモリー管理ソフトと思えば良いのだ. (注. ANSI/ISO C の規格では, このような場合にちゃんと領域を開放するかどうかは OS 依存らしい.) ただし, こういう考えでルーズに組まれたソフトを再利用しようとすると大変なことになる. このようなプログラムで問題となる程の "急速な" メモリーリークなら, 特別なツールを使わなくても, top コマンドで, 観察するだけで確認できる.
メモリーリークの防止策としては, garbage collector である Boehm GC を用いて領域の開放を自動的に行うことが考えられる. 手書きで free しないで, 自動 GC に任せる事にすると メモリー リークと ダングリング リファレンス の2つの問題をほぼ解消する事ができる. C, C++ のポインタの扱いで悩んでいるなら, GC の実行効率とのトレードオフを考慮したうえで, 採用を検討すると良い. GCC のソースが Boehm GC を標準で含んでいるので(GNU/Ada に使用), C, C++ のついでに GC もインストールしてしまうと良い.
究極的には, プロジェクトで使用する言語として, 自動 GC や 配列の添字範囲の検証機能などがある言語を使う. DJB のように, buffer overflow を防止するライブラリなどを作りこんでしまっても良い. ただし, 一般に, こういうわがままが通じるかどうかは怪しいが...
free では swap の使用量も観察できる. 起動後しばらくすると, swap にはみ出しているようにみえる事がある. これは,今あるメモリ−では不足しているという事なのか?
$ free total used free shared buffers cached ...略 Swap: 151192 48628 102564
swap にはみ出していること自体を気にする人もいるが,要点を取り違えている. 前節でメモリの空きを入出力のバッファとキャッシュに利用していると書いたが, 更に, 活動が少ない部分をメモリから排除して swap に追い出し, バッファやキャッシュに転用する. つまり, 通常, swap を使っているというのは, プログラムやライブラリのうちで実際にはほとんど使われていない部分を, カ−ネルがうまく検出してメモリ−から排除している様子を表しているのだ. これだけでは, メモリ−の不足とは云えない. free コマンドで swap が出ているのもそれだけなら全く問題無しだ.
$ free total used free shared buffers cached Mem: 1024764 960812 63952 0 162580 476356 -/+ buffers/cache: 321876 702888 Swap: 151192 48628 102564 $ vmstat 30 procs memory swap io system cpu r b w swpd free buff cache si so bi bo in cs us sy id 2 0 0 48628 64124 162532 476356 0 0 0 0 1 4 11 3 11 1 0 0 48628 64112 162540 476356 0 0 0 4 102 1768 98 2 0 1 0 0 48628 64112 162540 476356 0 0 0 11 104 1576 97 3 0 2 0 0 48628 64104 162548 476356 0 0 0 13 101 1605 98 2 0 1 0 0 48628 64092 162560 476356 0 0 0 5 104 1674 98 2 0 2 0 0 48628 64088 162564 476356 0 0 0 7 102 1796 97 3 0 2 0 0 48628 64084 162568 476356 0 0 0 4 103 1572 98 2 0 3 0 0 48628 64052 162568 476356 0 0 0 3 102 1705 97 3 0 1 0 0 48628 64048 162572 476356 0 0 0 7 110 1786 98 2 0emacs, TeX, Mozilla などに常用しているPCの様子.
もともとメモリー不足でプログラムが動かない事を回避するための SAWP なので, そのような場合には SWAP を増やすと良い. または. 資金が許せばメモリーを増設する.
そこで問題となるのは, メモリーとディスクの動作速度の違いで, メモリー不足を SWAP で補うと, その分, 動作が遅くなってしまうという問題だ. ここで, メモリーのコストと実行速度の トレードオフを考慮する必要が出てくる. この点を以下で見てみる.
メモリ−不足で気になるのは次の様な影響が出ないかって事だ.
"たまに" ページングが激しくて実行効率が低下したとしても, メモリー不足で実行できないよりはまし. このような緊急の場合の SWAP の動作を敵視する必要は無い. 定常的に swap の活動があるようなら, そのための入出力で動作が遅くなっていないかが問題となる. 多少の効率の低下が容認できるか確認すること.
メモリーが不足気味なら, メモリーを増強するかどうかを, 要求される速度とコストのトレードオフを含めて考慮しなければならない. それと, そもそも, メモリーの不足が起こっているのか, メモリーの増強で解決するのかを判断しなければならない.
プロセスのメモリ浪費は上で解説したように free, top, ps などでしらべる. 全体としてのメモリの活動状況としては,残りメモリ−や swap の大きさも参考にはなるけど, (つまり, 上の(1),(2) が起こる潜在的な危険性って意味で), 実行効率という面からの見所はディスク入出力の活動量ってことだ.
なにかプログラムを動かしはじめたときに一時的に so が出るのは問題無しだ. そのための swap だしね? また, 定常的であっても, 少々の si, so が出るだけなら, 単に活発に活動しているというだけなので, 問題は無い. (ここまでは, メモリーに余裕がある場合でも通常おこる動作.)
ここからが, 注目だよ!
si が定常的にあるのも, swap がうまく働いている(メモリの余裕は少ないが)事を意味するだろうから, あまり問題にはならない.(要求される速度にもよるが...)
so の量が多い状態が定常的に続くなら作業用メモリの不足を疑ってみる. 大きさの基準は, どの程度の能力を期待しているかにも依るので, 一概には云えないようだ. しかし, 書き込みに使う領域は swap されにくいようにしてあるので, so が定常的に多いのはかなりピンチと云える.
si や so の観察で, メモリ−が不足気味だと分かっても, CPU, I/O(ネットワ−ク, ディスク等), ネットワ−クサ−ビス(NFS, NIS, DNS 等) の問題が元にあって, その影響がメモリ−の負荷に現れている可能性もある. だから, メモリ−を増やすのが最善の対策かどうかは, まだ分からない. CPU や I/O の負荷も含めて総合的に考慮する必要がある. NFS などのネットワークサービスの問題が絡むと分析はすごく厄介な事になる.
$ vmstat 30 procs memory swap io system cpu r b w swpd free buff cache si so bi bo in cs us sy id 0 0 0 0 9652 788 146828 0 0 28 3 177 401 3 4 92 0 1 0 0 1648 852 141564 0 0 520 1 120 343 1 2 97 1 0 0 0 1628 852 119292 0 0 878 1 132 341 1 3 96 0 1 0 0 1628 536 97160 0 0 885 1 134 340 1 3 95 0 1 0 0 1688 356 75764 0 0 850 0 176 435 3 3 94 0 1 0 0 1640 356 62872 0 0 510 1 194 544 10 3 87 1 1 0 0 1640 184 40208 0 0 910 0 159 370 2 3 95 1 0 0 104 1628 148 12612 0 3 1118 1 161 364 2 9 89 0 1 0 5436 1640 148 12772 19 197 239 49 169 327 1 6 93 0 1 0 9184 1656 148 13768 27 151 122 38 147 354 1 2 98 0 0 0 12228 1720 148 14072 35 134 112 34 179 401 1 2 96 1 0 0 14640 2160 148 12512 115 81 40 21 211 595 3 2 95 1 0 0 18064 2444 148 12516 105 114 26 29 176 496 3 1 96 0 0 0 21220 2448 148 12612 102 105 30 27 175 486 3 2 95
一時的なら, 問題ない. また, 必要な能力を確保できているなら気にしない. そうで無い場合, サービスの遅延が問題になるなら, 更に検査が必要.
必要メモリーの量は, マシンが要求される反応速度と, SWAP の(ディスク入出力の)活動量のトレードオフを考慮して決めると良い.
vmstat の si と so の活動から判断する.
空きメモリーを増やして動作を軽くする事が目的. 不活発なコードを追い出すという意味で SWAP を確保する.
長時間動作させると, 活動が鈍い部分が SWAP に吐き出される. この吐き出された量の2〜3倍以上を考えると良いだろう.
SWAP を動作中のプロセスのメモリー要求が増大した場合の逃し先,という観点で評価する. この意味では,とにかく プロセスを動かし続けることを優先する.
古典的には SWAP はメインメモリーと同程度を確保することが推奨されている. これは, 動作に必要なメモリーを搭載したうえで, 2倍の安全率を考慮するという意味と考えて良い. SWAP が活発に使われるのは非常の場合なので, 動作が遅くなってもある程度許容する.
実メモリーを安全率も含んで大量に確保するという選択もありうる.
Kodama's home / tips.