OOM Killerについて
OOM Killerについて聞いたことがあるでしょうか。Linuxを使っている際に、メモリーが不足してOS自体が停止する恐れがあるような場合には、メモリーを多く使っているプロセスを強制的にKillすることで、メモリーを解放する仕組みが備わっています。これをOOM Killer(Out of Memory Killer)と言います。
ここでメモリーが不足している状態とは、物理メモリーとスワップ領域を共に使い切ってしまい、必要なメモリーを確保することが出来ない状態を言います。
OOMの無効化
OOMが発生した場合には、メモリーを多く使っているプロセスを強制的にkillするという、OOM Killerを無効化することが出来ます。ただし、メモリーを使い切ってしまっていることで、正常な動作ができなくなりシステムでパニックが発生してシステム全体が停止してしまう可能性があります。OOM KIllerが有効になっている場合であれば、メモリーを多く使っているプロセスを強制的に停止することでメモリーを解放しますから、システム全体が停止するようなことにはなりません。
OOM Killerの動作は、/proc/sys/vm/panic_on_oom
の値によって制御されています。通常、この値が`0
になっていてOOM Killerが有効化されています。
$ cat /proc/sys/vm/panic_on_oom
0
この値を1
に設定すると、OOM Killerが無効化されます。その結果、OOMが発生した場合にはパニックの発生する可能性があります。
$ echo 1 | sudo tee /proc/sys/vm/panic_on_oom
1
$ cat /proc/sys/vm/panic_on_oom
1
OOMの制御
OOM Killerを有効化した状態で、特定のプロセスがKillされないように制御することが出来ます。この制御は、oom_adj
とoom_score
という2つの値によって決められます。
ここで、oom_adj
は、-16
から15
の範囲で設定することが出来ます。oom_adj
の既定値は0
で子プロセスは親プロセスのoom_adj
の値を継承します。
OOM KIllerは、oom_score
の値が最も大きなプロセスを強制終了します。
$ ps -ef | grep bash | grep -v grep
alma 54062 54059 0 11:03 pts/0 00:00:00 -bash
$ cat /proc/54062/oom_score
666
$ cat /proc/54062/oom_adj
0
上記例では、現在実行しているシェルのPIDを調べて、そのシェルのoom_score
とoom_adj
の値を表示しています。
$ echo -5 | sudo tee /proc/54062/oom_adj
-5
$ cat /proc/54062/oom_score
471
上記プロセスのoom_adj
に-5
を設定した結果、oom_score
の値が小さくなりました。
さらに、oom_adj
には-17
という特別な値があり、この値を設定するとプロセスのOOM Killerが無効になります。
$ echo -17 | sudo tee /proc/54062/oom_adj
-17
$ cat /proc/54062/oom_score
0
プロセスのoom_adj
に-17
を設定した結果、oom_score
の値が0
になりました。この場合には、プロセスがOOM Killerで強制終了されなくなります。
ただし、このoom_adj
はLinux 2.5.46
以降では非推奨となっていて、代わりにoom_score_adj
が推奨されています。
oom_score_adj
は、各プロセスに0
(強制終了しない)から1000
(常に強制終了する)までの値を割り当てて、どのプロセスが強制終了の対象となるかを決定します。この値は、プロセスが割り当てることのできるメモリーの許容量に対する、現在のメモリーとスワップの使用量の割合から計算されています。例えば、許可されているメモリーを全て使用している場合には、スコア値が1000
となります。あるいは、許可されているメモリーの半分を使用している場合には、スコア値が500
となります。root
のプロセスは、他の場合よりも3%
多くのメモリーが許可されます。ここで、許可されるメモリーの量はOOM Killerが呼び出された条件によって異なります。例えば、システム全体のメモリー不足が原因の場合には、割り当て可能な全てのリソースとなります。
またoom_score_adj
の値を-1000
に設定すると、OOM Killerで強制終了されなくなります。
以前のカーネルとの下位互換のために、oom_score_adj
またはoom_adj
に書き込むと、もう一方がスケーリングされた値で変更されます。
例えば、次のように動作します。
$ cat /proc/54062/oom_score_adj
0
$ cat /proc/54062/oom_adj
0
$ echo 500 | sudo tee /proc/54062/oom_score_adj
500
$ cat /proc/54062/oom_adj
8
$ echo 4 | sudo tee /proc/54062/oom_adj
4
$ cat /proc/54062/oom_score_adj
235
oom_score
の計算方法
oom_score
の値は、次のようにして計算されています。
- 各プロセスのメモリーサイズでスコアを計算します。
- ここで、子プロセス(カーネルスレッドを含む)のメモリーサイズも加算されます。
- スコアは
nice
値によって増加します。 - 長時間実行している場合、または多くのCPU時間を消費している場合には減少します。
CAP_SYS_ADMIN
やCAP_SYS_RAWIO
が設定されている場合は減少します。- 計算された結果が、
oom_score_adj
やoom_adj
の値によって調整されます。
OOMが発生した場合には、これらの計算の結果oom_score
の値が最も大きなプロセスが強制終了されることになります。
その他のパラメーター
/proc/sys/vm/oom_dump_tasks
OOM Killerを実行する場合に、システム全体のプロセスダンプ(カーネルスレッドを除く)を作成するかどうかを制御する。値が0
の場合ダンプされない、値が0
以外の場合はダンプされる。(既定値: 0)/proc/sys/vm/oom_kill_allocating_task
OOMが発生した場合に、メモリー不足の原因となったプロセスをkillするかどうかを制御する。(既定値: 0)
この値が0
の場合スコアに基づいてkillするプロセスを選択する。0
以外の場合には、メモリー不足の原因となったプロセスをKillする。そのため、Killするプロセスを選択する処理を省略することができる。/proc/sys/vm/panic_on_oom
OOMが発生した場合に、カーネルパニックを引き起こすかどうかを制御する。(既定値: 0)
値が0
の場合、OOM KIllerの処置が実行される。値が1
の場合、パニックが発生する。しかし、メモリーポリシーやcpusets
によってメモリー割当てが制限されている場合には、プロセスがOOM Killerによってkillされるがパニックが発生しない場合もある。値が2
の場合には、OOMが発生するとカーネルが常にパニックを引き起こす。
値1
と2
はクラスタリングシステムにおけるフェールオーバー用として用意されている。フェールオーバーの考え方によって、どちらかの値を選択することができる。
まとめ
AlmaLinuxのLinuxとしての詳細な管理方法の一つであるOOM Killerについて見てみました。特にRaspberry Piのように小さな物理メモリーで使用する可能性のある場合には、メモリーとスワップ領域の合算による仮想記憶装置の容量と、そこで実行するアプリケーションで使用する可能性のあるメモリー容量についても注意を払っておくことが重要ではないでしょうか。
参考: 第16章 Out of Memory (OOM)状態の管理 低レイテンシー操作のためのRHEL 9 for Real Timeの最適化
E.3.12. /proc/PID/ RHEL 6 導入ガイド
Linux Programmer’s Manual (5) proc Linuxプログラマーズマニュアル
Documentation for /proc/sys/vm/ Kernelドキュメント