メモリボトルネックの原因を探る


表1.確認ポイントと項目

No 確認ポイント コマンドとオプション 確認する項目
@ 空きメモリは物理メモリの1/64を下回っているか? adb -k メモリ制御関連のカーネル変数。
pagesize 1ページあたりのバイト数。
sar -r freemem
vmstat free
A ページ走査数はいくつか? sar -g pgscan/s
vmstat sr
B スワップアウト、スワップインは発生していないか? sar -w swpot/s、swpin/s、bswot/s、bswin/s
vmstat so、si
vmstat w
C スワップは充分あるか? sar -r freeswap
vmstat swap
swap -s available
swap -l free
D ページイン、アウトの水準は? sar -g ppgin/s、ppgout/s
vmstat pi、po
vmstat de
mpstat mjf
vmstat -p【備考】 executableのepi、epo、epf
anonymousのapi、apo、apf
filesystemのfpi、fpo、fpf
E メモリ割り当て量は妥当か? sar -r freemem
sar -k sml_mem/alloc/fail
lg_mem/alloc/fail
ovsz_alloc/fail
crash kmastatで表示されるカーネルメモリ。
ps -efly RSS、SZ
ipcs -a SEGSZ
accton(採取)
acctcom(編集)
SIZE(K)
pmap -x kb
F アプリケーションプログラムの作りは妥当か? dump -h Size
G 共用ライブラリは適切か? ldd 表示される共用ライブラリ。

【備考】Solaris 8で新たにリリースされたオプションです。Solaris 7ではmemstatコマンドです。Solaris 2.6以前のバージョンでは提供されていません。


@空きメモリは物理メモリの1/64を下回っているか?

ページング処理は、sarコマンド-rオプションで表示される空きページ数 freemem が、物理メモリの1/64を下回ると始まります。この1/64のしきい値をlotsfree、またはcachefreeと言います。ユーザプログラムやカーネルが、より多くのページを要求した結果、空きページ数が物理メモリの1/128を下回ると、ページングのための、秒あたりページ走査数(後述A)が高くなります。1/128のしきい値をdesfreeと言います。さらにページが必要になり、空きページが物理メモリの1/256を下回ると、スワップ処理が始まります。1/256のしきい値をminfreeと言います。まず、これらのカーネル変数の値を確認してみましょう。

解説 データ
adbコマンド-kオプションで、アブソリュートデバッガを起動し、各カーネル変数の値を確認します。physmemは物理メモリの総ページ数です。adbは起動直後に、16進数でこれを表示します。16進数ではよくわからないので、10進数で表示しました。
"シンボル名/e" の、スラッシュの後ろに指定されている"e"は、64ビット(8バイト)を10進数で表示するadbコマンドです。マシンアーキテクチャが32ビット(4バイト)の場合は、"e"の代わりに"D"を使用します。
# adb -k <CR>
physmem 1eecb
physmem/e <CR>
physmem:
physmem: 126667
lotsfree/e <CR>
lotsfree:
lotsfree: 1955
cachefree/e <CR>
cachefree:
cachefree: 1955
desfree/e <CR>
desfree:
desfree: 977
minfree/e <CR>
minfree:
minfree: 488
$q <CR>

#

図1.1 カーネルのページング関連パラメタの確認

1ページの大きさは、pagesizeコマンドで知ることが出来ます。

解説 データ
これは簡単。pagesizeコマンドを起動するだけです。 # pagesize <CR>
8192
#

図1.2 ページサイズの表示

freememは、メモリの多すぎるシステムで大きな値を示します。適切にサイジングされたシステムは、lotsfreeの近辺で推移します。メモリが少な過ぎるシステムはlotsfreeを下回ります。表1.1にこの関係をまとめました。

表1.1 freememの評価

メモリ量 freememの範囲 評価
多い lotsfree < freemem 足りています。大きく離れていると、無駄があると言えます。
適切 lotsfree ≒ freemem 大丈夫です。但し、監視は必要です。
少ない freemem < lotsfree メモリの再サイジングが必要です。

メモリ不足のシステムでは、正常なレスポンスやスループットは全く期待できません。

解説 グラフ
16:20頃と、16:34頃に極度にfreememが少なくなっています。
シナリオ番号:2 os
16:20頃と、16:34頃のfreemem値を抜粋しました。desfreeやminfreeを下回っていることがわかります。すると、ページ走査数や、スワップ処理が行われていることが考えられます…
16時20分頃 16時34分頃
16:19:09 66737 16:34:07 104115
16:19:14 61228 16:34:12 104114
16:19:19 26698 16:34:17 87887
16:19:24 2436 16:34:22 52045
16:19:29 488 16:34:27 24592
16:19:34 482 16:34:32 3702
16:20:02 516 16:34:37 476
16:20:07 2176 16:34:42 487
16:20:12 2018 16:34:47 90478
16:20:17 82700 16:34:52 113194
16:20:22 82684 16:34:57 113192

図1.3 空きページ数 freemem


Aページ走査数はいくつか?

空きページ数がlotsfree(前述@)の近辺で、ページ要求のスピードが遅い場合、freememの回復はゆるやかです。sarコマンドの-gオプションで示される秒あたりのページ走査数pgscan/sは高くなりません。一方、ページ要求のスピードが速い場合、その要求に追いつくのと同時に、freememの回復を急ぐため、pgscan/sが高くなります。参考文献1はpgscan/sが200以上、参考文献2は250以上の場合、ページ不足であると判断基準に差があります。freememをlotsfreeに回復させるため、カーネルのページング処理が走る訳ですから、本コンテンツでは0(ゼロ)が望ましいと考えています。

解説 グラフ
16:20頃と、16:34頃に極度にpgscan/sが高くなっています。
シナリオ番号:2 os
16:20と、16:34頃のpgscan/sを抜粋しました。この処理は、メモリをスィープアウト(掃除)するプロセスを実行したものです。
16時20分頃 16時34分頃
16:19:09 0 16:34:07 0
16:19:14 0 16:34:12 0
16:19:19 0 16:34:17 0
16:19:24 7982.4 16:34:22 0
16:19:29 10568.2 16:34:27 0
16:19:34 9798.22 16:34:32 3466.2
16:20:02 10040.59 16:34:37 8398.64
16:20:07 616.39 16:34:42 8298
16:20:12 185.44 16:34:47 1226.75
16:20:17 0 16:34:52 0
16:20:22 0 16:34:57 0

図2.ページ走査 pgscan/s


Bスワップアウト、スワップインは発生していないか?

freememが、カーネル変数minfree(メモリの1/256。前述@)を下回ると、強制的にスワップ処理が走ります。スワップ処理が走るようなシステムでは、レスポンスは全く期待できません。また、プロセスは期待する時間に制御をもらえないため(たとえば、性能情報を採取する本sarコマンドのような)、時間スタンプさえも狂ってきます(図2 ページ走査pgscan/s内の時間スタンプに注目して下さい。5秒毎のはずが、何と28秒もかかっています! 驚きですよね!!)。

解説 グラフ
16:20頃に記録されたsarコマンド-wオプションで表示されるswpot/sとswpin/sです。
シナリオ番号:2 os(部分)
16:20頃に記録されたsarコマンド-wオプションで表示されるbswot/sとbswin/sです。
シナリオ番号:2 os(部分)

図3.スワップ処理


Cスワップは充分あるか?

スワップ領域のサイズは、物理メモリと同じ、物理メモリの2倍、いや3倍、はては5〜6倍など諸説あります。それほどサイズの根拠を明らかに出来ないシロモノなのでしょうか? 答えは、「必要なサイズを割当てる」と簡単です(実のところ、この「必要なサイズ」を求めるのが大変な事なのですが…)。では、どのように必要なサイズを決めるのでしょうか? ここで、スワップ領域はどのように利用されるのかを考えてみます。スワップ領域に入れられるのは、(1)プロセスのデータ(ヒープ)セグメント (2)プロセスのスタックセグメント の2種類です。共有メモリも、プロセスのヒープセグメントの一種です。それも、プロセス実行時に「うつわ」をスワップ領域に割り当て、ページアウトが発生した場合に、初めてメモリからスワップ領域にコピーされるのです【注意】。スワップ領域はまた、パニックが発生した場合、カーネルメモリイメージの書き込み領域として使用されます。通常の設定では、カーネルと、カーネルメモリ部分のみパニックイメージが採取されます。このため、物理メモリのサイズを超えることはありません。プロセスのテキストセグメント(インストラクション部分)やファイルデータは、元々「ファイル名」を持っていますので、スワップ領域は使用されません。プロセスのデータ(ヒープ)セグメントとスタックセグメントは「名前無し」のため、スワップ領域が使用されるのです。
これらを表4にまとめました。

表4.スワップ領域を使用するセグメント

セグメント名 スワップの
領域使用
解説
データ プログラムのコンスタントや作業領域等のデータ部分です。ページアウト、インの対象です。
ヒープ mallocで割り当てた部分です。ページアウト、インの対象です。
プライベート型共有メモリ 親子プロセス間で共有するメモリです。ページアウト、インされることがあります。
ISM【備考】型共有メモリ × 他プロセスでもアクセス出来る共有メモリです。スワップ領域は割り当てられますが、ページアウト、インされません。
スタック システムコールやライブラリコールの軌跡が保持される部分です。
テキスト × インストラクション部分です。ファイル名があるので、スワップ領域は使用されません。ページアウト時はそのページがフリーされます。再びページインされる場合、ファイルから読み込まれます。

 

【注意】 dfコマンド-kオプションでスワップ領域を見ると、"/tmp"というディレクトリが、"/var/run"と同じ"swap"になっています。これはtmpfsと呼ばれるファイルシステムです。皆さんは決してこの領域を使用してはいけません。なぜなら、/tmpにファイルを作成すると、スワップ領域を侵食してしまうため、本来の目的である「データとスタックのためのスワップ領域」が少なくなってしまうからです。過去、/tmpをむやみに使用した結果、システムダウンになった例をたくさん見てきました。ご注意下さい。詳細は、Solarisのtmpfsとスワップ領域についてをご覧下さい。
【備考】 ISM(Intimate Shared Memory:親和型共有メモリ)型の共有メモリは、物理メモリをヒープとして直接使用できる機能です。ORACLEがこの型の共有メモリを使用しています。JavaもISM型共有メモリを使用することがあります(オプション)。

 

以上のことから、スワップ領域の大きさは、次の式で求められます。

スワップ領域 = データセグメント + ヒープセグメント + プライベート型共有メモリセグメント + ISM型共有メモリセグメント + スタックセグメント
(何れも最大値を代入します)

計算結果が物理メモリよりも小さい場合は、物理メモリと同じサイズをスワップ領域に割り当てます。

解説 グラフ
16:20頃と、16:34頃に極度にfreeswapが極度に少なくなっています。単位はブロックで、1ブロック512バイトです。
シナリオ番号:2 os
16:20と、16:34頃のfreeswapを抜粋しました。この処理は、メモリをスィープアウト(掃除)するプロセスを実行したものです。
16時20分頃 16時34分頃
16:19:09 2075277 16:34:07 2599648
16:19:14 1987082 16:34:12 2599648
16:19:19 1434614 16:34:17 2340032
16:19:24 1024835 16:34:22 1766582
16:19:29 843571 16:34:27 1327344
16:19:34 666157 16:34:32 984979
16:20:02 386714 16:34:37 816243
16:20:07 203807 16:34:42 692829
16:20:12 179175 16:34:47 2198508
16:20:17 2060909 16:34:52 2600464
16:20:22 2060890 16:34:57 2600464

図4.空きスワップブロック freeswap


Dページイン、アウトの水準は?

SUN SPARCマシンのメモリはデマンドページングです。デマンドページングとは、メモリをアクセスした時、もしそのページがメモリ上に無い場合、ページフォルトが発生し、補助記憶装置(通常はディスク)からページを読み込んでくることを言います。このようなディスク入出力を伴うページフォルトを、メジャーフォルトと言います。一方、アクセスした時、そのページが過去アクセスされたことがあり、空きリスト中に保持されている場合、そのページを再利用します。この場合のページフォルトを、マイナーフォルトと言います。

解説 グラフ
sarコマンド-gオプションで表示される秒あたりにページアウトされた数ppgout/sと、-pオプションで表示される秒あたりにページインされた数ppgin/sです。
シナリオ番号:7 os
mpstatで表示されるメジャーフォルトmjfです。
シナリオ番号:7 cpu
上記のケースのfreememは右のようになっています。16:07頃まで、極めて厳しい空きメモリ状態になっていたものです。
シナリオ番号:7 os
同じく、上記のケースのpgscan/sです。16:07頃を境に、メモリ不足が解消されています。
シナリオ番号:7 os

図5.1 マイナーフォルトとメジャーフォルト

では、このページイン、アウトの内訳はどのようになっているのでしょうか? Solaris 7はmemstatコマンド、Solaris 8はvmstatコマンド-pオプションの出力がページングの内訳を表示出来るようになりました。Solaris 2.6以前のバージョンでは、これらの機能は提供されていません。。

解説 グラフ
vmstatコマンドの秒あたりにフリーにしたページfr、一時的な不足状態deの表示です。
シナリオ番号:7 os
api、apo、apfはanonymous(名前無し)、すなわちスワップ領域とのページングを示しています。apiはanonymousページイン、apoはanonymousページアウトです。apfはanonymousページフリーで、apoと等価です。
シナリオ番号:7 os
epi、epo、epfは実行モジュールのページングを示しています。epiはexecutableページイン、epoはexecutableページアウトです。epoは実際にページアウトする訳ではありませんので記録されないようです。これは、epfのexecutableページフリーに記録されます。
シナリオ番号:7 os
fpi、fpo、fpfはファイルシステムのページングを示しています。fpiはfilesystemページイン、fpoはfilesystemページアウト、fpfはfilesystemページフリーで、fpoと等価です。
シナリオ番号:7 os

図5.2 vmstat -pの出力


Eメモリ割り当て量は妥当か?

メモリは大きく6個の要素に分けられます。(1)UNIXカーネル本体 (2)カーネルメモリ (3)ページ構造体の配列 (4)空きメモリ (5)ユーザメモリ、 および (6)ディスクバッファキャッシュです。表6に、各々のサイズの見方と目安を示します。

表6.メモリ要素の見方とサイズの目安

No 要素 見方 目安
(1) UNIXカーネル カーネルシンボル、physinstalledの値からphysmemの値を引いたサイズです。pysinstalledは、adbコマンド-kオプションで、e、またはDファンクションで表示します。 概ね300キロバイト程度です。
(2) カーネルメモリ sarコマンド-kオプションで表示されるsml_mem、lg_mem、およびovsz_allocの合計です。crashコマンドのkmastatファンクションはカーネルメモリの詳細をリストします。 最大で物理メモリの25パーセントといわれています。システムの構成や使い方で大きく変化します。
(3) ページ構造体配列 物理メモリページ数×64バイトです。 構成メモリサイズで変化します。
(4) 空きメモリ sarコマンド-rオプションのfreememです。 物理メモリページの1/64です。
(5) ユーザメモリ psコマンド-eflyオプションで表示されるRSS、SZはページ単位のプロセスサイズです【備考1】。psコマンドで表示出来ないプロセスは、プロセスアカウントのSIZE(K)を確認します【備考2】。セグメントの詳細は、pmapコマンドの-xオプションで計測しますユーザメモリを調査するをご覧下さい。。データ、ヒープ、テキスト、およびスタックセグメントのKb(キロバイト)項目で表示される値を合計します。テキスト、共有メモリ、および共用コードはシェアされますので、システムで唯一と考えます【備考3】。共有メモリは、ipcsコマンド-aオプションで表示します。 物理メモリから上記(1)〜(4)、および(6)を引いたサイズです。
(6) ディスクバッファキャッシュ 全ファイルシステムに構成されているファイル使用量を、dfコマンド-kオプションで合計します。合計値の1〜2パーセントです。 1〜2パーセントは巨大なサイズになることがあります。全部のアプリケーションを実行している時、(4)の空きメモリfreememが物理メモリの1/64以上であればOKです。

【備考】

1. RSS、SZは、データ、ヒープ、テキストの他に共有メモリ、共用コード等、全てのサイズが合計されています。
2. acctcomの出力で表示されるSIZE(K)には、mallocで割り当てたヒープサイズは反映されません。
3. 同一プログラム名で、同じディレクトリ下にあるものが共用されます。名前が同じでも、ディレクトリが別の場合は共用されません。


Fアプリケーションプログラムの作りは妥当か?

/usr/ccs/bin/dumpコマンドは、実行プログラム、またはオブジェクトファイルの内容をリストしてくれます。-hオプションはセクションヘッダーと呼ばれるプログラムの詳細なリストを表示してくれます。リスト内のデータやテキストのSizeで示される値が参考になります。プログラムで注意する点は、コンスタントや定数を僅かに変更して、別の名前でコンパイルする場合です。テキスト部分が共用されませんので、無駄が出ることがあります。このような場合は、外部からパラメタで入力し、ロジックで処理を考慮すると、テキスト部分を共用することが出来ます。いくつかのプロセスが共通のデータを参照する場合、共有メモリ化することでメモリの節約になります。いずれも、プログラム改修コストと、メモリコスト等を総合的に判断して対策を実施する必要があります。


G共用ライブラリは適切か?

lddコマンドは実行プログラムが参照するダイナミックライブラリの一覧表を表示してくれます。目的のディレクトリに正しくおさまっているかどうかを確認します。幾つかのプログラムで共通に使用する関数やルーチンを共用コードにして、ダイナミックライブラリにすると、テキスト部分を共用出来、メモリを節約することが出来ます。


Copyright (C) 2004 by The Art of Computer Technologies, Corp.  All rights reserved.