NTTグループの各社で鳴らした俺たちLinuxトラブルシューティング探偵団は、各社で培ったOSS関連技術を手に、NTT OSSセンタに集められた。普段は基本的にNTTグループのみを相手に活動しているが、それだけで終わる俺たちじゃあない。
ソースコードさえあればどんなトラブルでも解決する命知らず、不可能を可能にし、多くのバグを粉砕する、俺たちLinuxトラブルシューティング探偵団! 助けを借りたいときは、いつでもいってくれ!
OS:高田哲生
俺はリーダー、高田哲生。Linuxの達人。俺のようにソースコードレベルでOSを理解している人間でなければ、百戦錬磨のLinuxトラブルシューティング探偵団のリーダーは務まらん。
Web:福山義仁
俺は、福山義仁。Web技術の達人さ。ApacheのようなWebサーバからTomcat、JBossみたいなJava、アプリケーション技術まで、何でも問題を解決してみせるぜ。
DBMS:下垣徹
下垣徹。PostgreSQLの達人だ。開発からサポートまで何でもやってみせらぁ。でも某商用DBMSだけは勘弁な。
HA:田中 崇幸
よぉ! お待ちどう。俺さまこそHAエキスパート。Heartbeatを使ってクラスタを構成する腕は天下一品! HAが好きなんて奇人? 変人? だから何? HaHaHaHa!!
番外編もついに最終回! Linuxトラブルシューティング探偵団の活躍もひとまずの終了を迎えるぜ! 最後はメモリ不足騒動の顛末(てんまつ)。さらにOSの奥深くへ踏み込んだ内容になっていくが、最後までついてきてくれ!
前回までで「カーネル空間」の「物理メモリ」を消費し過ぎた結果、OS停止に至った可能性があるというところまで突き止めました。今回は、カーネル空間のどの部分を消費し過ぎていたのか、さらには根本的な原因は何だったのかを追求していきます。
カーネル空間の物理メモリといっても、まずはどの部分のメモリを消費しているのか把握しなければなりません。これを把握するには/proc/meminfoを見るのが最も簡単です。/proc/meminfoの出力例は以下のようなものでした。
MemTotal: 2073208 kB |
上記の値については、原則として以下のような計算式が成り立ちます。
MemTotal=MemFree+Active+Inactive+Slab+
VmallocUsed(※)+PageTables
今回重要なのは、この式(1)です。式(1)を図示すると図1のようになります。
第1回で説明したとおり、InactiveとMemFreeを足したものが利用可能なメモリです。第1回で説明していないVmallocUsed、Slab、PageTablesはカーネル内で確保する領域です。これらについてもう少しだけ詳しく説明しておきます。
VmallocUsed(※)は、カーネル内のvmalloc()というAPI経由で確保されるメモリを想定しています。この領域は、ドライバなどのカーネルモジュールによって確保されることが多く、システムがいったん起動してしまうとあまり増減しません。ただ、x86_64でMMCONFIG(注1)を利用している場合、カーネル内の仮想メモリを256MiB(注2)予約しており、/proc/meminfoのVmallocUsedにはこの値が足し込まれます。しかし実際は、よほどデバイス数が多くない限り、実際に使っているのは数Mbytes程度です。
そこでこの際、MMCONFIG用に予約されている256MiBはVmallocUsedから引いてしまいましょう。具体的には256Mbytes=262144KbytesをVmallocUsedから引いたものを、上記式(1)のVmacllocUsed(※)として計上します。
なお、MMCONFIGを使っているかどうかは下記のコマンドで確認できます。MMCONFIGを使っていなければ、VmallocUsedの値をそのまま使用してください。
# dmesg | grep MMCONFIG |
Slabは、kmalloc()というAPIでメモリを確保する仕組みで、スラブアロケータという仕組みで管理されています。スラブアロケータはカーネル内のメモリプールで、メモリの断片化を防ぐ仕組みが入っており、確保/解放を繰り返すような使い方をするメモリに使われます。
PageTablesは、ページテーブルエントリという「ページ」の管理構造体として利用されているメモリです。ページとは、カーネル内におけるメモリの管理単位で、vmalloc()で確保したメモリにしろ、kmalloc()で確保したメモリにしろ、メモリは基本的にこの単位で割り当てられます。サイズは物理メモリ量に応じて決まり、一度システムが起動してしまえば変化しません。
これらはカーネル内の領域なので、解放することはできません。Activeと併せて「解放不可能なメモリ」ということでまとめられます。
注1:Memory Mapped Configuration。デバイスへメモリを割り当てる設定方法の一種
注2:メビバイト。1MiB=2^20 Bytes=1,048,576Bytesとなり、1MBytes(=1000000Bytes)とは値が異なる。
/proc/meminfoは第1回で出てきましたが、詳しく説明していませんでした。その出力が意味するところを説明してしまいましょう。
項目名 | 説明 |
---|---|
MemTotal | システム全体で利用できる物理メモリの総容量。システム起動時に計算される。その後、この値が変化することはない |
MemFree | システム全体で利用できる物理メモリの空き容量 |
Buffers | ファイルなどのメタデータとして使用している物理メモリの総容量 |
Cached | ファイルデータのキャッシュなどに使用している物理メモリの総容量。共有メモリは Cached に加算される。SwapCachedは含まない |
SwapCached | 物理メモリ上にキャッシュされたスワップページの総容量 |
Active | 最近アクセスした(とカーネルが思っている)物理メモリの容量 |
Inactive | 最近アクセスしていない(とカーネルが思っている)、解放してよい物理メモリの容量 |
HighTotal | Highmem領域にある物理メモリの容量。x86アーキテクチャ(32bit)にのみ存在し、通常、896Mbytesを超える物理メモリはこの領域で扱われる |
HighFree | Highmem領域にある物理メモリの空き容量。x86アーキテクチャ(32bit)のみ存在 |
LowTotal | Lowmem領域にある物理メモリの容量(MemTotal-HighTotal)の値。x86アーキテクチャ(32bit)の場合、0xc0000000〜0xf8000000の間の896MBytesの範囲。x86_64アーキテクチャ(64bit)の場合、すべてのメモリがLowmem領域で扱われる |
LowFree | Lowmem領域にある物理メモリの空き容量。(MemFree-HighFree)の値 |
SwapTotal | スワップ領域の総容量。使用/未使用にかかわらずすべてのパーティション/ファイルのスワップ領域が含まれる。swapon/swapoffコマンドによるスワップ領域の増減も反映される |
SwapFree | スワップ領域の空き容量。使用しているすべてのスワップ領域の空きと未使用のすべてのスワップ領域が含まれる |
Dirty | ディスクとの同期が取れていない物理メモリの総容量 |
Writeback | ディスクへ書き出し中の物理メモリの総容量 |
Mapped | ページテーブルに登録されている物理メモリの総容量。ページキャッシュと無名ページの両方が含まれる。最近のカーネルでは、AnonPagesとMappedに分離 |
Slab | スラブアロケータで使用されている物理メモリの総容量 |
CommitLimit | 仮想メモリを取得できるかどうかの判断に使われる閾値。 ((vm.overcommit_ratio×物理メモリ量)+スワップ量)の値。vm.overcommit_memory=2のときにのみ使われる。vm.overcommit_memory=0 or 1のときにはまったく関係ない |
Committed_AS | 全プロセスによって確保された仮想メモリの総容量。vm.overcommit_memory=2のときにこの値がCommitLimitより大きいとメモリ不足と判定され、malloc()などが失敗する |
PageTables | ページテーブルエントリで使用されている物理メモリの容量 |
VmallocTotal | vmalloc()で利用可能な仮想メモリ領域の容量。x86_64アーキテクチャの場合、定数 |
VmallocUsed | vmalloc()で確保された物理メモリ領域とMMCONFIGで確保しているメモリ領域の総容量 |
VmallocChunk | vmalloc()で確保された仮想メモリ領域のfree領域の中で最も大きい連続領域の容量 |
HugePages_Total | hugepageとして確保された物理メモリの総量 |
HugePages_Free | HugePages_Free |
Hugepagesize | Hugepagesize |
Active+Inactive=AnonPages+Cached+Buffers+SwapCached
式(2)の中にあるAnonPagesとは、/proc/meminfoの出力内にはありませんが、無名ページ(Anonymous Page)の領域を表しています。無名ページとは、第2回でも少しだけ説明しましたが、ユーザープロセスがmalloc()などで確保したり、プログラム本体用に利用するメモリ領域です。
出力例を見てもらえば分かりますが、AnonPagesは/proc/meminfoには出力されません。RHEL 5など最近のバージョンのカーネルには入っているのですが、RHEL 4時点ではこの値は存在しませんでした。従って、RHEL 4でAnonPagesを把握したい場合は、式(2)の計算式で求めることになります。
Copyright © ITmedia, Inc. All Rights Reserved.