Show Table of Contents
3.7. memory
memory サブシステムは、cgroup 内のタスクによって使用されるメモリーリソースの自動レポートを生成し、他のタスクによるメモリー使用の上限を設定します。
- memory.stat
- 以下の表に記載した、広範囲なメモリーの統計をレポートします。
表3.2 memory.stat によりレポートされる値
統計 説明 cachetmpfs(shmem) を含むページキャッシュ (バイト単位)rsstmpfs(shmem) を含まない匿名のスワップキャッシュ (バイト単位)mapped_filetmpfs(shmem) を含むメモリーマップドファイルのサイズ (バイト単位)pgpginメモリー内へページされたページ数 pgpgoutメモリーからページアウトされたページ数 swapスワップの使用量 (バイト単位) active_anontmpfs(shmem) を含む、アクティブな最長時間未使用 (LRU) 一覧上の匿名のスワップキャッシュ (バイト単位)inactive_anontmpfs(shmem) を含む、非アクティブ LRU 一覧上の匿名のスワップキャッシュ (バイト単位)active_fileアクティブ LRU 一覧にある、ファイルと関連づけされたメモリー (バイト単位) inactive_file非アクティブ LRU 一覧にある、ファイルに関連付けされたメモリー (バイト) unevictable再生不可のメモリー (バイト単位) hierarchical_memory_limitmemorycgroup が含まれる階層のメモリー制限 (バイト単位)hierarchical_memsw_limitmemorycgroup が含まれる階層のメモリーとスワップの制限 (バイト単位)また、これらのファイルの中で、hierarchical_memory_limitおよびhierarchical_memsw_limit以外のファイルには、それぞれ、total_というプレフィックスの付いた対応ファイルがあり、cgroup についてだけでなく、その子グループについてもレポートします。たとえば、swapは cgroup によるスワップの使用量をレポートし、total_swapは cgroup とその子グループによるスワップの使用量をレポートします。memory.statによってレポートされた値を解析する際には、さまざま統計が相互に関連している点に注意してください。active_anon+inactive_anon= 匿名メモリー +tmpfsのファイルキャッシュ + スワップキャッシュしたがって、active_anon+inactive_anon≠rssとなります。これは、rssにtmpfsが含まれないのが理由です。active_file+inactive_file= cache - size oftmpfs
- memory.usage_in_bytes
- cgroup 内のプロセスによる現在のメモリー総使用量をレポートします (バイト単位)。
- memory.memsw.usage_in_bytes
- cgroup 内のプロセスによる現在のメモリー使用量と使用済みスワップ領域の和をレポートします (バイト単位)。
- memory.max_usage_in_bytes
- cgroup 内のプロセスによるメモリー最大使用量をレポートします (バイト単位)。
- memory.memsw.max_usage_in_bytes
- cgroup 内のプロセスによるスワップメモリー最大使用量と使用済みスワップ領域をレポートします (バイト単位)。
- memory.limit_in_bytes
- ユーザーメモリーの最大値 (ファイルキャッシュを含む) を設定します。単位が指定されていない場合、その値はバイト単位と解釈されますが、より大きな単位を示すサフィックスを使用することが可能です (キロバイトには
kまたはK、メガバイトにはmまたはM、ギガバイトにはgまたはG)。root cgroup を制限するのには、memory.limit_in_bytesは使用できません。値を適用できるのは、下位階層のグループに対してのみです。memory.limit_in_bytesに-1と書き込み、現行の制限値を削除します。 - memory.memsw.limit_in_bytes
- メモリーとスワップ使用量の合計の最大値を設定します。単位が指定されていない場合、その値はバイト単位と解釈されますが、より大きな単位を示すサフィックスを使用することが可能です (キロバイトには
kまたはK、メガバイトにはmまたはM、ギガバイトにはgまたはG)。root cgroup を制限するのに、memory.memsw.limit_in_bytesは使用できません。値を適用できるのは、下位階層のグループに対してのみです。memory.memsw.limit_in_bytesに-1と書き込み、現行の制限値を削除します。重要
memory.limit_in_bytesパラメーターは、memory.memsw.limit_in_bytesを設定する前に 設定しておくことが重要となります。逆の順序で設定を試みると、エラーが発生します。これは、memory.memsw.limit_in_bytesを使用できるようになるのが、(memory.limit_in_bytesで事前に設定されている) メモリー制限をすべて使い切った後のみであるためです。次の例を検討してください: 特定の cgroup に対してmemory.limit_in_bytes = 2Gとmemory.memsw.limit_in_bytes = 4Gと設定すると、cgroup 内のプロセスが 2 GB のメモリーを割り当てることが可能となり、それを使い果たすと、さらに 2 GB のスワップのみを割り当てます。memory.memsw.limit_in_bytesパラメーターはメモリーとスワップの合計を示しています。memory.memsw.limit_in_bytesパラメーターが設定されていない cgroup 内のプロセスは、(設定されているメモリーの上限を消費した後に) 使用可能なスワップをすべて使い果たしてしまい、空きスワップがなくなるために Out Of Memory (OOM) の状態を引き起こす可能性があります。また、/etc/cgconfig.confファイルでmemory.limit_in_bytesとmemory.memsw.limit_in_bytesのパラメーターを設定する順序も重要です。この設定の正しい例は以下のとおりです。memory { memory.limit_in_bytes = 1G; memory.memsw.limit_in_bytes = 1G; } - memory.failcnt
memory.limit_in_bytesに設定されているメモリーの上限値に達した回数をレポートします。- memory.memsw.failcnt
memory.memsw.limit_in_bytesに設定されているメモリーとスワップ領域の合計が上限に達した回数をレポートします。- memory.force_empty
0に設定されている場合には、cgroup 内のタスクによって使用される全ページのメモリーを空にします。このインターフェイスは、cgroup がタスクを持たない時にのみ使用できます。メモリーを解放できない場合は、可能ならば 親 cgroup に移動されます。cgroup を削除する前には、memory.force_emptyを使用して、未使用のページキャッシュが親 cgroup に移動されないようにしてください。- memory.swappiness
- ページキャッシュからページを再生する代わりに、カーネルがこの cgroup 内のタスクで使用されるプロセスメモリーをスワップアウトする傾向を設定します。これはシステム全体用に
/proc/sys/vm/swappiness内に設定されているのと同じ傾向で、同じ方法で算出されます。デフォルト値は60です。これより低い値を設定すると、カーネルがプロセスメモリーをスワップアウトする傾向が低減します。また100以上に設定すると、カーネルはこの cgroup 内のプロセスのアドレス領域となる部分のページをスワップアウトできるようになります。0の値に設定しても、プロセスメモリーがスワップアウトされるのを防ぐことはできない点に注意してください。グローバル仮想メモリー管理ロジックは、cgroup の値を読み取らないため、システムメモリーが不足した場合に、依然としてスワップアウトが発生する可能性があります。ページを完全にロックするには、cgroup の代わりにmlock()を使用してください。以下にあげるグループの swappiness は変更できません。/proc/sys/vm/swappinessに設定された swappiness を使用している root cgroup- 配下に子グループがある cgroup
- memory.use_hierarchy
- cgroup の階層全体にわたって、メモリー使用量を算出すべきかどうかを指定するフラグ (
0または1) が含まれます。有効 (1) となっている場合、メモリーサブシステムはメモリーの上限を超過しているプロセスとその子プロセスからメモリーを再生します。デフォルト (0) では、サブシステムはタスクの子からメモリーを再生しません。 - memory.oom_control
- cgroup に対して Out of Memory Killer を有効化/無効化するフラグ (
0または1) が含まれています。これを有効にすると (0)、許容量を超えるメモリーを使用しようとするタスクは OOM Killer によって即時に強制終了されます。OOM Killer は、memoryサブシステムを使用するすべての cgroup でデフォルトで有効になっています。これを無効にするには、memory.oom_controlファイルに1と記載します。~]#
echo 1 > /cgroup/memory/lab1/memory.oom_controlOOM Killer が無効になると、許容量を超えるメモリーを使用しようとするタスクは、追加のメモリーが解放されるまで一時停止されます。memory.oom_controlファイルは、現在の cgroup の OOM ステータスもunder_oomエントリにレポートします。cgroup がメモリー不足の状態で、その cgroup 内のタスクが一時停止されている場合には、under_oomエントリで値が1とレポートされます。memory.oom_controlファイルは、通知 API を使用して OOM 状態の発生をレポートすることができます。詳しくは、「通知 API の使用」 および 例3.3「OOM の制御と通知」 を参照してください。
3.7.1. 使用例
例3.3 OOM の制御と通知
以下の例は、cgroup 内のタスクが許容量を超えるメモリーの使用を試みた場合に OOM Killer がどのように対応し、通知ハンドラーが OOM 状態のどのようにレポートするかを示した実例です。
memoryサブシステムを階層に接続し、cgroup を作成します。~]#
mount -t memory -o memory memory /cgroup/memory~]#mkdir /cgroup/memory/bluebluecgroup 内のタスクが使用できるメモリーを 100 MB に設定します。~]#
echo 104857600 > memory.limit_in_bytesblueディレクトリに移動して、OOM Killer が有効になっていることを確認します。~]#
cd /cgroup/memory/blueblue]#cat memory.oom_controloom_kill_disable 0 under_oom 0- 現在のシェルプロセスを
bluecgroup のtasksファイルに移動し、このシェルで起動したその他すべてのプロセスが自動的にbluecgroup に移動するようにします。blue]#
echo $$ > tasks - ステップ 2 で設定した上限を超える大容量のメモリーを割り当てようとするテストプログラムを起動します。
bluecgroup の空きメモリーがなくなるとすぐに OOM Killer がテストプログラムを強制終了し、標準出力にKilledをレポートします。blue]#
~/mem-hogKilled以下は、このようなテストプログラムの一例です。[5]#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define KB (1024) #define MB (1024 * KB) #define GB (1024 * MB) int main(int argc, char *argv[]) { char *p; again: while ((p = (char *)malloc(GB))) memset(p, 0, GB); while ((p = (char *)malloc(MB))) memset(p, 0, MB); while ((p = (char *)malloc(KB))) memset(p, 0, KB); sleep(1); goto again; return 0; } - OOM Killer を無効にし、テストプログラムを再度実行します。今回は、テストプログラムが一時停止の状態のままとなり、追加のメモリーが解放されるのを待機します。
blue]#
echo 1 > memory.oom_controlblue]#~/mem-hog - テストプログラムが一時停止されている間は、cgroup の
under_oom状態が変わり、空きメモリーが不足していることを示している点に注意してください。~]#
cat /cgroup/memory/blue/memory.oom_controloom_kill_disable 1 under_oom 1OOM Killer を再度有効にすると、テストプログラムは即時に強制終了されます。 - すべての OOM 状態についての通知を受信するためには、「通知 API の使用」 に記載したようにプログラムを作成してください。以下はその一例です[6]。
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/eventfd.h> #include <errno.h> #include <string.h> #include <stdio.h> #include <stdlib.h> static inline void die(const char *msg) { fprintf(stderr, "error: %s: %s(%d)\n", msg, strerror(errno), errno); exit(EXIT_FAILURE); } static inline void usage(void) { fprintf(stderr, "usage: oom_eventfd_test <cgroup.event_control> <memory.oom_control>\n"); exit(EXIT_FAILURE); } #define BUFSIZE 256 int main(int argc, char *argv[]) { char buf[BUFSIZE]; int efd, cfd, ofd, rb, wb; uint64_t u; if (argc != 3) usage(); if ((efd = eventfd(0, 0)) == -1) die("eventfd"); if ((cfd = open(argv[1], O_WRONLY)) == -1) die("cgroup.event_control"); if ((ofd = open(argv[2], O_RDONLY)) == -1) die("memory.oom_control"); if ((wb = snprintf(buf, BUFSIZE, "%d %d", efd, ofd)) >= BUFSIZE) die("buffer too small"); if (write(cfd, buf, wb) == -1) die("write cgroup.event_control"); if (close(cfd) == -1) die("close cgroup.event_control"); for (;;) { if (read(efd, &u, sizeof(uint64_t)) != sizeof(uint64_t)) die("read eventfd"); printf("mem_cgroup oom event received\n"); } return 0; }上記のプログラムはコマンドラインの引数として指定された cgroup 内の OOM 状態を検出し、mem_cgroup oom event receivedの文字列を使用して標準出力にレポートします。 bluecgroup の制御ファイルを引数として指定して、上記の通知ハンドラープログラムを別のコンソールで実行します。~]$
./oom_notification /cgroup/memory/blue/cgroup.event_control /cgroup/memory/blue/memory.oom_control- 別のコンソールで
mem_hogテストプログラムを実行し、OOM 状態を発生させてoom_notificationプログラムがそれを標準出力にレポートするのを確認します。blue]#
~/mem-hog

Where did the comment section go?
Red Hat's documentation publication system recently went through an upgrade to enable speedier, more mobile-friendly content. We decided to re-evaluate our commenting platform to ensure that it meets your expectations and serves as an optimal feedback mechanism. During this redesign, we invite your input on providing feedback on Red Hat documentation via the discussion platform.