メモリの監視と利用

はじめに

第13章はじめに

時代が進むにつれ、システムはメモリ リソースを要求するようになりました。同時にRAMの価格が下がり、かつパフォーマンスが向上してきました。それでも、システム全体のパフォーマンスとスループットのボトルネックはメモリに関連していることがよくあります。CPUとI/Oサブシステムでは、メモリからのデータの取得やメモリへのデータの書き込みで待たされることがあります。メモリに関するシステムの動作監視、デバッグ、調整のため、多くのツールがあります。


学習目標
この章の終わりまでに、次のことができるようになります。

メモリ チューニングに関する重要な（相互に関連する）検討事項とタスクを一覧表示できます。
/proc/sys/vmのエントリの使用と、/proc/meminfoの解読ができます。
vmstatを使用して、メモリ、ページング、I/O、プロセッサ アクティビティ、およびプロセスのメモリ消費に関する情報を表示できます。
OOM-killerが処理を実行するタイミングを決定する方法を理解し、メモリを解放するために消去するプロセスを選択できます。


メモリの監視と利用

メモリ監視
メモリ サブシステムのチューニングは複雑なプロセスになる場合があります。まず、メモリ使用量とI/Oスループットは本質的に関連していることに注目する必要があります。ほとんどの場合、メモリの大部分はディスク上のファイルのコンテンツをキャッシュするために使用されます。

したがって、メモリ パラメータを変更すると、I/Oパフォーマンスに大きな影響を与える可能性があります。同様に、I/Oパラメータを変更すると、仮想メモリ サブシステムに大きな逆効果を及ぼす可能性があります。

/proc/sys/vmのパラメータを調整するときのベスト プラクティスは、一度に1つずつ調整して効果を探すことです。重要な（相互に関連する）タスクは次のとおりです。

フラッシング パラメータの制御。すなわち、ダーティにすることが許可されているページの数と、ディスクにフラッシュされる頻度の制御です。
スワップ動作の制御。すなわち、他にバッキングストアがないためにスワップアウトする必要があるページとは対照的に、ファイルの内容を反映するページをメモリに残すことができる量の制御です。
多くのプログラムは、特にコピーオンライト（COW）技術によって、要求するメモリの全量を必要としないため、メモリのオーバーコミットを許可する量を制御できます。

メモリのチューニングは微妙な場合が多く、あるシステムの状況や負荷で効果があるものでも、他の状況では最適とはほど遠い場合があります。

さらに、システム全体のパフォーマンスとスループットのボトルネックに、メモリが関連していることがよくあります。CPUとI/Oサブシステムでは、メモリからのデータの取得やメモリへのデータの書き込みで待たされることがあります。

表：メモリ監視ユーティリティ

ユーティリティ　内容　パッケージ
free　メモリ使用量の概要の表示　procps
vmstat　　動的に更新される、仮想メモリ統計とブロックI/Oの詳細情報　　procps
pmap　プロセスのメモリ マップの表示　procps
 
使用する最も簡単なツールはfreeです。

c7:/tmp> free -m

      total used  free shared buff/cache available
Mem:  15901 2946  2080   9317       4502     12457
Swap:  8095    0  8095

/proc/meminfo
疑似ファイル/proc/meminfoには、メモリの使用方法に関する豊富な情報が含まれています。

$ cat /proc/meminfo

MemTotal: 16275080 kB
MemFree:  3117968 kB
MemAvailable: 11260960 kB
Buffers: 1115028 kB
Cached: 7785520 kB
SwapCached: 87488 kB
Active: 6206148 kB
Inactive: 6132824 kB
Active(anon): 3086828 kB
Inactive(anon): 1124176 kB
Active(file): 3119320 kB
Inactive(file): 5008648 kB
Unevictable: 117096 kB
Mlocked: 32 kB
SwapTotal: 21580796 kB
SwapFree: 21471740 kB
Dirty: 264 kB
Writeback: 0 kB
AnonPages: 3189032 kB
Mapped: 986784 kB
Shmem: 772612 kB
KReclaimable: 351196 kB
Slab: 506264 kB
SReclaimable: 351196 kB
SUnreclaim: 155068 kB
KernelStack: 17760 kB
PageTables: 91492 kB
NFS_Unstable: 0 kB
Bounce:  0 kB
WritebackTmp: 0 kB
CommitLimit: 29718336 kB
Committed_AS: 13371052 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 33060 kB
VmallocChunk: 0 kB
Percpu: 6080 kB
HardwareCorrupted: 0 kB
AnonHugePages: 815104 kB
ShmemHugePages: 0 kB
ShmemPmdMapped: 0 kB
CmaTotal: 0 kB
CmaFree: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
Hugetlb: 0 kB
DirectMap4k: 249932 kB
DirectMap2M: 13254656 kB
DirectMap1G: 4194304 kB

下の表にリストされている内容を調べてエントリを理解できると、役に立ちます。

テーブル：/proc/meminfoのエントリ

エントリ　　意味
MemTotal　　使用可能なRAMの合計（物理メモリからカーネル予約メモリを引いたもの）
MemFree　　低ゾーンおよび高ゾーンの両方の空きメモリ
Buffers　　一時的なブロックI/Oストレージに使用されるメモリ
Cached 　　ページキャッシュ メモリ。主にファイルI/O用
SwapCached　　スワップ後も、まだスワップ ファイルにあるメモリ
Active　　最近使用されたメモリ。最初に要求されることはありません。
Inactive　　最近使用されていないメモリ。再利用に適しています
Active（anon）	匿名（anonymous）ページとして利用しているメモリ
Inactive（anon）	匿名（anonymous）ページとして利用していないメモリ
Active（file）	file-backed ページとして利用しているメモリ
Inactive（file）	file-backed ページとして利用していないメモリ
Unevictable	メモリからスワップしたり解放したりできないページ
Mlocked	　　メモリにロックされているページ
SwapTotal　　使用可能なスワップ領域の総容量
SwapFree　　スワップ領域の空容量
Dirty　　ディスクに書き戻す必要があるメモリ
Writeback	積極的にディスクに書き戻されるメモリ
AnonPages　　キャッシュ内のfile-backedではないページ
Mapped　　ライブラリなどにマップするために使用しているメモリの総量
Shmem　　共有メモリに使用されるページ（容量）
Slab　　スラブで使用されるメモリ
SReclaimable　　スラブ内の再利用可能なキャッシュ メモリ
SUnreclaim　　再利用できないスラブ内のメモリ
KernelStack　　カーネル スタックで使用されるメモリ
PageTables　　ページテーブル構造で使用されているメモリ
Bounce	　　ブロック デバイスのバウンス バッファに使用されるメモリ
WritebackTmp　　ライトバック バッファ用にFUSEファイルシステムで使用されるメモリ
CommitLimit　　オーバーコミットを含む、使用可能なメモリの合計
Committed_AS　　使用されているかどうかにかかわらず、現在割り当てられている合計メモリ
VmallocTotal 　　vmallocでの割り当てに使用できるカーネル内のメモリの合計
VmallocUsed　　vmallocの割り当てで実際に使用されるメモリ
VmallocChunk　　利用可能な最大隣接のvmalloc領域
HugePages_Total　　hugeページ プールの合計数
HugePages_Free　　まだ割り当てられていないhugeページ
HugePages_Rsvd　　予約されているが、まだ使用されていないhugeページ
HugePages_Surp　　オーバーコミッションに使用される余剰のhugeページ
Hugepagesize 　　hugeページのサイズ
 
今見ているエントリは、実行しているカーネルのバージョンによって異なることに注意してください。


/proc/sys/vm
/proc/sys/vmディレクトリには、仮想メモリ システムを制御するための多くの調節用のノブ（つまみ）が含まれています。このディレクトリに表示される内容は、カーネルのバージョンによって多少異なります。ほとんどすべてのエントリは（root権限で）書き込み可能です。

これらの値は、エントリに直接書き込むか、sysctlユーティリティを使用して変更できます。さらに、/etc/sysctl.confを変更することにより、ブート時に値を設定できます。

カーネル ソース（またはディストリビューションのカーネル ドキュメント パッケージ）の/proc/sys/vmディレクトリの完全なドキュメントは、Documentation/sysctl/vm.txtにあります。

テーブル：/proc/sys/vmのエントリ

エントリ　　意味
admin_reserve_kbytes　　特権ユーザー用に予約されている空きメモリ量
block_dump　　ブロックI/Oのデバッグを有効にします
compact_memory　　カーネルの設定でmemory compactionが有効になっている場合に、メモリ圧縮（基本的にはデフラグメンテーション）をオンまたはオフにします
dirty_background_bytes　　コミットされていないページをディスクへの書き込むトリガーとなるダーティ メモリのしきい値
dirty_background_ratio　　カーネルがダーティ データのディスクへの書き込みを開始する、ダーティ ページの割合
dirty_bytes　　プロセスが自分で書き込みを開始する、ダーティ メモリの量
dirty_expire_centisecs　　ダーティ データの保存期間（単位は100分の1秒）
dirty_ratio　　プロセスが自分でダーティ データの書き込みを開始するページの割合
dirty_writeback_centisecs　　ライトバック デーモンが起動する定期的な間隔。この値を0に設定すると、定期的な自動ライトバックはありません。
drop_caches　　echoで1を指定するとページ キャッシュを解放、2を指定するとdentryキャッシュと inodeキャッシュを解放、3を指定するとすべてを解放。クリーンなキャッシュ ページだけが解放されることに注意してください。syncを実行して、最初にダーティ ページを書き込んでおく必要があります。
extfrag_threshold　　カーネルがメモリを圧縮するタイミングを制御
hugepages_treat_as_movable　　hugeページの処理方法を切り替えるために使用
hugetlb_shm_group 　　System Vのhugeページに使用できるグループIDを設定
laptop_mode　　ラップトップの電力を節約するために、いくつかの機能を制御可能
legacy_va_layout　　メモリ マッピングの表示方法に古いレイアウト（カーネル 2.4）を使用
lowmen_reserve_ratio　　そのメモリにしか存在できないページのために低いアドレスのメモリをどの程度確保するかを制御。つまり、代わりに高いアドレスのメモリに移動できるページは移動します。Hugeメモリを搭載した32ビット システムでのみ重要です。
max_map_count　　プロセスが持つことができるメモリ マップ領域の最大数。デフォルトは64K です。
min_free_kbytes　　各ゾーンで予約する必要がある最小空きメモリ
mmap_min_addr　　ユーザー プロセスがメモリ マップできないアドレス空間の量。セキュリティ上の目的で使用され、偶発的なカーネルのnull参照がアプリケーションで使用する最初のページを上書きするバグを回避します。
nr_hugepages　　hugeページ プールの最小サイズ
nr_pdflush_hugepages 　huge ページ プールの最大サイズ　=nr_hugepages*nr_overcommit_hugepages
nr_pdflush_threads 　　pdflushスレッドの現在の数。書き込み不可です。
oom_dump_tasks　　有効にするとoom-killerが割り込んだときにダンプ情報が生成されます。
oom_kill_allocating_task　　設定すると、oom-killerは最適な方法を選択するのではなく、メモリ不足の状況を引き起こしたタスクを強制終了します。
overcommit_kbytes 　　overcommit_ratioかこのエントリのいずれかを設定できます。両方は設定できません
overcommit_memory　　値が0の場合、オーバーコミットは有効で、カーネルは空きメモリがどれだけ残っているかをみて割り当てます。1 の場合、オーバーコミットは有効で、実メモリ以上に割り当てを許可します。2の場合、オーバーコミットは無効です。
overcommit_ratio　 overcommit_memory = 2の場合に使用。メモリは、スワップの大きさ + RAMの内、このパーセンテージまで使うことができます。
page-cluster　　スワップするために一度に書き込むことができるページ数デフォルトは3です
panic_on_oom　　メモリ不足の状況の時にシステムがクラッシュするようにします
percpu_pagelist_fraction　ホットプラグ可能なCPUマシンの、各ゾーンのそれぞれのCPUに割り当てられたページの割合
scan_unevictable_pages　　ここに書き込まれると、システムはスキャンしてページを移動し、それらを再利用可能にします
stat_interval 　　vmstatによってvmの統計情報が更新される頻度（デフォルトは1秒）
swappiness　　カーネルをどれだけ積極的にスワップすべきかの頻度
user_reserve_kbytes　　 overcommit_memoryが2に設定されている場合、ユーザーがどれくらいメモリ リソースを使えるかを設定します。
vfs_cache_pressure　　カーネルがinodeとdentryキャッシュに使用されたメモリを、どの程度積極的に再利用する必要があるかを設定します。デフォルトは100です。 0の場合、このメモリはメモリ不足のため再利用はされません。


vmstat
vmstat は、メモリ、ページング、I/O、プロセッサ アクティビティ、およびプロセスに関する情報を表示する多目的ツールです。多くのオプションがあります。コマンドの一般的な形式は次のとおりです。

$ vmstat [options] [delay] [count]

遅延が秒単位で指定されている場合、レポートはその間隔でcount回繰り返されます。countが指定されない場合、vmstatは、Ctrl-Cなどのシグナルによって強制終了されるまで、統計を永久にレポートし続けます。

他の引数が指定されていない場合、vmstatが表示する内容は、最初の行は最後に再起動された以降の平均を示し、2行目以降は指定された間隔でのアクティビティを示しています。

$ vmstat 2 4

vmstatの使用例

オプション-S mが指定された場合、メモリ統計の単位はKBではなくMBになります。

-aオプションを使用すると、vmstatはアクティブおよび非アクティブなメモリに関する情報を表示します。アクティブなメモリ ページとは、最近使用されたページです。クリーン（ディスクの内容が最新）の場合、またはダーティ（最終的にディスクにフラッシュする必要がある）の場合があります。対照的に、非アクティブなメモリ ページは最近使用されていずクリーンである可能性が高く、メモリに負荷がかかるとすぐに解放されます。

$ vmstat -a 2 4

メモリは、アクティブ リストと非アクティブ リストの間を行ったり来たりします。これは、新しく参照されたり、使用と使用の間隔が長くなったりするためです。

vmstat -SM -a 2 4 コマンドとその出力のスクリーンショット

ディスクの統計情報の表を取得するには、-dオプションを使用します。

vmstatを使用してディスク統計情報の表を取得

1つのパーティションのみの簡単な統計情報を取得する場合は、-pオプションを使用します。 

1つのディスクでvmstatを使用する例


OOM Killer
メモリの負荷に対処する最も簡単な方法は、空きメモリが使用可能である限りメモリ割り当てを成功させ、すべてのメモリを使い切ったら失敗することです。

最も簡単な方法の2番目は、ディスク上のスワップ領域を使用して、常駐メモリの一部をコアから転送することです。この場合、（少なくとも理論上の）使用可能なメモリの合計は、実際のRAMにスワップ領域のサイズを加えたものになります。難しいのは、負荷が出たときにスワップアウトするメモリのページを把握することです。このアプローチでは、スワップ領域自体がいっぱいになった場合、新しいメモリを要求しても失敗する必要があります。

ただし、Linuxは優れています。Linuxでは、システムにメモリをオーバーコミットすることを許可するため、RAMとスワップのサイズを超えるメモリ要求を許可できます。これは無謀に思えるかもしれませんが、（ほとんどではないにしても）多くのプロセスは、要求されたすべてのメモリを使用することはありません。

例として、1MBのバッファを確保してもメモリの数ページのみを使用するプログラムがあります。また別の例として、子プロセスがforkされるたびに親のメモリ空間全体のコピーを受け取る場合があります。LinuxはCOW（書き込み時コピー）技術を使用するため、プロセスの1つがメモリを変更しない限り、実際のコピーを作成する必要はありません。ただし、カーネルではコピーを実行する可能性があると想定する必要があります。

したがって、カーネルはメモリのオーバーコミットを許可しますが、ユーザー プロセス専用のページに対してのみです。カーネル内で使用されるページはスワップせずに、要求時に常に割り当てられます。

/proc/sys/vm/overcommit_memoryの値を設定することにより、このオーバーコミッションを変更したり、無効にすることもできます。

0：（デフォルト設定）オーバーコミットを許可しますが、明らかなオーバーコミットは拒否し、rootユーザーには、一般のユーザーよりもいくらか多くのメモリを割り当てます。
1：すべてのメモリ リクエストはオーバーコミットできます。
2：オーバーコミットをオフにします。メモリ コミットの合計が、スワップ領域のサイズと構成変更可能なパーセンテージ（デフォルトでは50）のRAMのサイズとの合計に達すると、メモリ要求は失敗します。このパーセンテージは/proc/sys/vm/overcommit_ratioで変更できます。

使用可能なメモリが使い果たされると、LinuxはOOM-killer（Out Of Memory）を呼び出して、メモリを開放するためにどのプロセスを終了するかを決定します。

これを行うための明瞭な方法はありません。アルゴリズムはヒューリスティックでなければならず、全員を満足させることはできません。多くの開発者は、OOM-killerの目的は、通常の操作の一部ではなく、正常なシャットダウンを許可することと考えています。

Andries Brouwerがこれについての面白い見解を示しました。

「航空機会社は、より少ない燃料で飛行機を飛ばす方が格安であることを発見しました。飛行機はより軽くなり、燃料の使用はより少なくなり、お金の節約が実現しました。しかし、まれなケースですが、燃料の量が不足し飛行機が墜落することがありました。この問題は、特別なOOF（out-of-fuel：燃料切れ）メカニズムを開発した会社のエンジニアによって解決されました。緊急の場合、乗客が一人選択され、飛行機から放り出されました。（必要に応じて、この手順が繰り返されました。）多数の理論が開発され、放り出される犠牲者を適切に選択する問題に関して多くの発表がありました。犠牲者はランダムに選ばれるべきか？ それとも、最も体重が重い人を選ぶべきか？ それとも年長者を選ぶべきか？ 乗客は、追い出されないようにお金を支払うべきだが、そうすると犠牲者は機内で最も貧しい人になるのか？ さらに、例えば最も重い人が選ばれた場合、それがパイロットだったら特別な例外があるべきか？ ファースト クラスの乗客は免除されるべきか？ 現在もOOFメカニズムは存在しており、時々稼働しています。そして、燃料不足がなくても乗客を放り出します。エンジニアは、今もこの誤動作がどのように引き起こされるかを研究しています。」

システムを生き続けさせるために何を犠牲にするかを決定するため、システム上の各プロセスのbadnessと呼ばれる値が計算され（/proc/[pid]/oom_scoreから読み取ることができます）、強制終了する順序はこの値によって決定されます。

同じディレクトリ内の２つのエントリを使用して、強制終了の可能性を高くしたり低くしたりできます。oom_adjの値は、badnessポイントを調整するビット数です。通常のユーザーは可能性を高くすることだけができます。低くすること（oom_adjの負の値）は、スーパーユーザーのみが指定できます。oom_adj_scoreの値は、badnessポイント値を直接調整します。oom_adjの使用は推奨されませんので注意してください。


演習

課題 13.1:OOM Killer を呼び出す

🚩
以下のPDFドキュメントに埋め込まれた外部URLにアクセスする場合は、常に右クリックして新しいタブまたはウィンドウで開いてください。直接クリックしてURLを開こうとすると、コース ウィンドウ／タブが閉じます。

Exercise 13.1: Invoking the OOM Killer

Examine what swap partitions and files are present on your system by examining/proc/swaps.
Turn off all swap with the command
$ sudo /sbin/swapoff -a

Make sure you turn it back on later, when we are done, with
$ sudo /sbin/swapon -a

Now we are going to put the system under increasing memory pressure. One way to do this is to exploit the stress-ng program we installed earlier, running it with arguments such as:
$ stress-ng -m 12 -t 10s

which would keep 3 GB busy for 10 seconds.

You should see theOOM(Out of Memory) killer swoop in and try to kill processes in a struggle to stay alive. You can see whatis going on by runningdmesgor monitoring/var/log/messagesor/var/log/syslog, or through graphical interfaces thatexpose the system logs.

Who gets clobbered first?


知識チェック

「第13章 - メモリの監視と利用」を完遂しました。おめでとうございます。このクイズに答えて、これまでに学んだ概念の理解度をチェックしてください。

クイズ開始


問題 13.1
すべてのスワップ パーティションを無効にすると、システムがOOM-killerを呼び出す可能性が高くなります。True or False?

A. True
B. False

問題 13.2
ファイル キャッシュに使用されるメモリは、システム プロセスで使用されるメモリよりも優先されます。OOM-killerは、ファイル キャッシュとユーザー プロセスの両方に十分なメモリがない場合に呼び出されます。True or False?

A. True
B. False

問題 13.3
スワップ領域に移されたものは、メイン メモリに戻されません。True or False?

A. True
B. False

問題 13.4
/proc/meminfoのMemFreeエントリは、使用されていないメモリの量を示します。アプリケーションがより多くのメモリを必要とする場合、カーネルはキャッシュが使用していたメモリを解放するため、ファイル キャッシュは空きメモリと見なすこともできます。True or False?

A. True
B. False


