Swap を有効化した環境における OOM
一般的に Swap を有効化した環境ではそうでない環境よりも OOM Killer が invoke される頻度は減ものの、それでもプロセスが要求するメモリ量を Swap で賄えなくなった場合は OOM によりプロセスが Kill される。
実際に挙動を確認するため、以下のようなコードで検証を実施してみる。
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#define BUFFER_SIZE (2000*1024*1024)
#define NCYCLE 30
#define PAGE_SIZE 4096
int main(void) {
char *p;
pid_t pid;
pid = getpid();
char pidStr[12];
snprintf(pidStr, 12, "%d", pid);
char str1[] = "echo -17 > /proc/";
char str2[] = "/oom_adj";
char *command_tmp;
char *command;
command_tmp = strcat(str1, pidStr);
command = strcat(command_tmp, str2);
system(command);
p = malloc(BUFFER_SIZE);
if (p == NULL)
err(EXIT_FAILURE, "malloc() failed.");
int i;
for (i = 0; i < BUFFER_SIZE; i += PAGE_SIZE) {
p[i] = 0;
int cycle = i / (BUFFER_SIZE/NCYCLE);
if (cycle != 0 && i % (BUFFER_SIZE/NCYCLE) == 0) {
sleep(1);
}
}
exit(EXIT_SUCCESS);
}
上記コードでは 2 GB 分の仮想メモリ領域を確保し、その領域に実際にアクセスすることで、物理メモリ領域を圧迫する。
また、自身の PID を取得し、/proc/[PID]/oom_adj に -17 を書き込むことにより、このプロセスが OOM Killer により kill されないようにしている。
なお、試す場合はオーバーコミットポリシーを OVERCOMMIT_ALWAYS にしておき、システムのメモリ量を大幅に超えても仮想メモリ領域を確保できるようにする必要がある。ちなみに今回は 1 GB のメモリを搭載したホストで検証を行う。
$ sudo bash -c "echo 1 > /proc/sys/vm/overcommit_memory"
$ cat /proc/sys/vm/overcommit_memory
1
$ free
total used free shared buffers cached
Mem: 1009432 267876 741556 64 21440 170396
-/+ buffers/cache: 76040 933392
Swap: 524284 0 524284
Swap 領域は 500 MB ほど。
$ swapon -s
Filename Type Size Used Priority
/swapfile file 524284 0 -2
では早速コンパイルしてバックグラウンドで実行する (バックグラウンドで実行しないと SSH のセッションが切られてプロセスが終了するため)。
$ gcc -o oom oom.c
$ sudo ./oom &
[1] 24423
上記を実行するとこちらからの入力を一切受け付けなくなり、セッションが切断される様子が確認できる。
Connection to 52.26.127.65 closed by remote host.
Connection to 52.26.127.65 closed.
結果
コンソール出力を見てみると、OOM Killer が invoke されていることがわかる。また、Swap cache stats から Free swap が 0kB であることも併せて確認可能。
なお、その後 killable なプロセスが無くなってシステムは再起動した。
[43373.298270] oom invoked oom-killer: gfp_mask=0x14201ca(GFP_HIGHUSER_MOVABLE|__GFP_COLD), nodemask=(null), order=0, oom_score_adj=-1000
[43373.308932] oom cpuset=/ mems_allowed=0
...
[43373.712031] Swap cache stats: add 137282, delete 137231, find 352/836
[43373.719424] Free swap = 0kB
[43373.723246] Total swap = 524284kB
[43373.727479] 262045 pages RAM
[43373.731361] 0 pages HighMem/MovableOnly
[43373.737251] 9687 pages reserved
[43373.741326] [ pid ] uid tgid total_vm rss nr_ptes nr_pmds swapents oom_score_adj name
[43373.751339] [ 1580] 0 1580 2880 1 12 3 233 -1000 udevd
[43373.761851] [ 2250] 0 2250 13252 0 26 3 106 -1000 auditd
[43373.771828] [ 2530] 0 2530 20148 4 41 3 204 -1000 sshd
[43373.783899] [ 2619] 0 2619 1628 1 8 3 30 0 agetty
[43373.797922] [ 2622] 0 2622 1091 1 8 3 23 0 mingetty
[43373.808510] [ 2626] 0 2626 1091 1 8 3 23 0 mingetty
[43373.824982] [ 2628] 0 2628 1091 1 8 3 23 0 mingetty
[43373.847313] [ 2630] 0 2630 1091 1 8 3 24 0 mingetty
[43373.873998] [ 2632] 0 2632 1091 1 8 3 24 0 mingetty
[43373.886506] [ 2634] 0 2634 1091 1 7 3 23 0 mingetty
[43373.900702] [ 2637] 0 2637 2879 1 11 3 233 -1000 udevd
[43373.909388] [23247] 0 23247 2879 1 11 3 232 -1000 udevd
[43373.919122] [24424] 0 24424 513056 231718 715 5 130284 -1000 oom
[43373.927345] Out of memory: Kill process 2619 (agetty) score 0 or sacrifice child
[43373.939239] Killed process 2619 (agetty) total-vm:6512kB, anon-rss:0kB, file-rss:4kB, shmem-rss:0kB
なお、SwapIn/Out の大量発生により、Disk に対する IOPS も高騰している点が確認できる。
これが Swap が有効化されていない環境と比較した時の大きな違いとなる。