メモリ使用状況の分析
メモリは、ユーザアプリケーションやカーネルを実行するために必要なリソースです。Linuxにおけるメモリ管理の仕組みは複雑で、その仕組みはカーネルのバージョンアップとともに改良されています。ここではメモリ使用状況を分析するにあたって、ポイントとなるいくつかの考え方を紹介します。
まず、メモリ使用状況について誤解されやすい点について触れておきます。
Linuxは、メモリに空きがあれば可能な限りディスクキャッシュとして確保することで、次回以降の読み込みを高速化しています。このキャッシュ確保によって空きメモリ(MemFree)が少なく見えますが、空きメモリ不足時にはカーネルの判断でキャッシュが解放され、空きメモリとして再利用できます。また、Javaアプリケーションなどでは、アプリケーションが使用するメモリの最小/最大サイズを指定できますが、実際に使用されるメモリは、アプリケーションが割り当てたメモリにデータを書き込んだ分となります。
このような特性から、メモリはCPUとは異なり、必ずしもスループットに比例してメモリ使用量が増加するわけではありません。メモリ使用状況を分析する際には、システム負荷の平常時とピーク時で比較することが望ましいです。
利用可能メモリについて
メモリ使用状況について、性能観点で特に意識しておきたいのは利用可能なメモリです[5]。空き(未使用な)メモリが不足すると、必要なメモリを確保するため、カーネルの判断で次のような動作が行われます。
- ディスクキャッシュの一部を解放
- スラブキャッシュ(カーネルの各種資源のキャッシュ)の一部を解放
- 利用頻度の低いメモリをディスクへスワップアウト
- それでもメモリが確保できなければ、CPUやメモリ使用状況などから問題になりにくそうなプロセスを強制終了
スワップが頻発することで処理遅延を招くおそれがあることから、利用可能メモリを簡単に表現すると、
「空きメモリ+解放可能なキャッシュ」
ということになります。
なお、全てのキャッシュを解放可能と見なすことは、性能観点からは望ましくないと考えられます。この理由は2つあります。
1つは、キャッシュサイズが小さくなると、キャッシュを利用する処理で遅延するおそれがあるためです。また、このような状況下ではカーネルの判断によって、キャッシュを解放せずにスワップアウトが選択されることがあります。
もう1つは、キャッシュの解放待ちに伴う処理遅延です。WriteI/Oによって更新されたキャッシュはDirtyと呼ばれ、まだディスクに書き込みが完了していない状態です。このDirtyなキャッシュを解放する際には、ディスク書き込みが完了するまで待ちが発生します。
それでは、このような仕組みを念頭において、メモリ使用状況を確認していきましょう。
注
[5]: ここでいう利用可能メモリとは、すでに使用中のメモリは含めません。
大まかなメモリ使用状況の分析
vmstat
は、CPU、メモリ、ストレージに関する情報を出力するコマンドです。取得粒度が粗いため詳細な分析には不向きですが、大まかなメモリ使用状況をリアルタイムに確認する用途に向いています。
vmstat 10 | awk '{print(strftime("%Y/%m/%d %H:%M:%S"),$0);fflush();}'
2015/10/26 13:13:57 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- 2015/10/26 13:13:57 r b swpd free buff cache si so bi bo in cs us sy id wa st 2015/10/26 13:13:57 1 0 3084 109320 124712 628832 0 0 0 28 0 0 0 0 100 0 0 2015/10/26 13:14:07 0 0 3084 108948 124712 629000 0 0 0 100 112 113 0 0 100 0 0 2015/10/26 13:14:17 0 0 3084 108940 124696 628976 0 0 0 108 111 113 0 0 100 0 0 2015/10/26 13:14:27 1 0 3084 109072 124712 629000 0 0 0 102 95 113 0 0 100 0 0
項目 | 意味 |
---|---|
swpd | スワップ領域の使用量(kB) |
free | 空きメモリ(kB) |
buff | メタデータ用キャッシュの使用量(kB) |
cache | ディスクキャッシュの使用量(kB) |
si | スワップイン※された量(kB/秒) |
so | スワップアウト※された量(kB/秒) |
※スワップインは、スワップ領域(ディスク)からメモリへ書き出す処理。スワップアウトは逆に、メモリからスワップ領域(ディスク)へ書き出す処理。
なお、vmstat
コマンドが初回に出力するデータは、サーバ起動時からの平均値です。
大まかな利用可能メモリの算出
まずは、大まかな利用可能メモリとして「free
+cache
」で算出し、安全率として8割程度で見ておくとよいでしょう[6]。この式は多少誤差を含むものの、利用可能メモリ不足をなるべく簡易にチェックすることを意図しています。厳密に見るとbuff
も加算対象といえますが、cache
と比べるとbuff
は相対的にサイズが小さいため、安全側に倒す意味でも加算は行わずに評価してよいでしょう。
より実態に近い利用可能メモリは、後述する/proc/meminfoから確認します。
注
[6]: RHEL7以降では「free
+cache
」ではなく、/proc/meminfoのMemAvailableで利用可能メモリを確認してください。
分析のポイント
利用可能メモリに十分な余裕があるか
余裕の判断基準はシステム特性によりますが、基本的には物理メモリ総量の2割を下回っておらず、かつ今後アプリケーションが使用する可能性のあるメモリを確保可能かどうかで判断するとよいでしょう。例えば、Javaアプリケーションで使用する最大メモリサイズを6GBで設定しているけれども、まだ2GBしか使われていなければ、今後さらに4GB使用される可能性があります。
vmstat
コマンドではOS全体のメモリ使用状況しかわかりませんが、ここからさらに、メモリ使用量の多いプロセスを特定するにはps -eF --sort=rss
コマンドが便利です。
ps -eF --sort=rss
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD root 2521 1 0 9734 32792 0 Dec03 ? 00:00:00 iscsiuio oracle 3333 1 0 262892 34068 0 Dec03 ? 00:00:12 xe_lgwr_XE gdm 4114 4011 0 75251 48320 0 Dec03 ? 00:00:00 /usr/libexec/gdmgreeter root 32659 1 0 613773 54732 0 Dec08 ? 00:00:02 /usr/java/jdk1.8.0_65/bin/java -Dderby.system.home=/home/web oracle 3520 1 0 260687 56844 0 Dec03 ? 00:00:11 xe_cjq0_XE oracle 3349 1 0 260500 69088 0 Dec03 ? 00:00:19 xe_mmon_XE oracle 3361 1 0 260245 79392 0 Dec03 ? 00:00:01 xe_s000_XE root 30332 1 0 626351 112860 0 Dec04 ? 00:00:27 /usr/bin/java -Djava.util.logging.config.file=/home/tomcat/t oracle 3341 1 0 260682 142436 0 Dec03 ? 00:00:27 xe_smon_XE oracle 3329 1 0 264204 183620 0 Dec03 ? 00:00:35 xe_dbw0_XE root 22892 1 1 698821 227684 0 Dec09 ? 02:21:27 /usr/java/jdk1.8.0_65/bin/jconsole root 32663 32612 0 572295 510828 0 Dec08 ? 00:06:24 /usr/java/jdk1.8.0_65/bin/java -server -Xms256m -Xmx512m -XX root 24770 24689 0 730598 561680 0 Dec07 ? 00:01:01 java -D[Standalone] -server -XX:+UseCompressedOops -verbose:
RSS(Resident Set Size)は、スワップされていない物理メモリ使用量(kB)を意味します。ps -eF --sort=rss
コマンドは、RSSの昇順でプロセスの一覧を表示します。
なお、RSSの値は共有メモリを含んでおり、その分はプロセス間で重複カウントされます(単純にRSSを合算してもOS全体のメモリ使用量とは一致しません)。プロセス間共有メモリの使用量を確認するには、後述する/proc/meminfoの解説を参考にしてください。
利用可能メモリが時系列経過とともに減少しているか
利用可能メモリの減少傾向が見られる場合、メモリリークが発生している可能性があります。メモリ使用量が増加し続けているプロセスが存在するか確認しましょう。なお、スラブキャッシュが肥大化している可能性もあるため、後述する/proc/meminfoで詳細を確認します。
siおよびsoが頻発しているか
siおよびsoが頻発している場合(すなわち0でない値が定常的に計上されている場合)、メモリ不足が発生している可能性が高いです。スワップアウトは利用頻度の低いメモリをディスクに書き込むため、I/O待ちに伴う処理遅延を招くおそれがあります。
なお、利用可能メモリに余裕があるように見える状況でも、スワップアウトがたまに発生するケースがあります。これはカーネルの判断で、空きメモリやキャッシュをなるべく確保するため、利用頻度の低いメモリをスワップアウトしてるからです。この場合は、iostat
コマンドの結果などでI/O待ちがとくに発生していなければ問題ありません。したがって、あくまで「siとsoの両方が」「定常的に」発生しているかどうかという観点で確認します。