第13回 AlmaLinuxのOOM Killerについて

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_adjoom_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_scoreoom_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_adjLinux 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の値は、次のようにして計算されています。

  1. 各プロセスのメモリーサイズでスコアを計算します。
  2. ここで、子プロセス(カーネルスレッドを含む)のメモリーサイズも加算されます。
  3. スコアはnice値によって増加します。
  4. 長時間実行している場合、または多くのCPU時間を消費している場合には減少します。
  5. CAP_SYS_ADMINCAP_SYS_RAWIOが設定されている場合は減少します。
  6. 計算された結果が、oom_score_adjoom_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が発生するとカーネルが常にパニックを引き起こす。

    12はクラスタリングシステムにおけるフェールオーバー用として用意されている。フェールオーバーの考え方によって、どちらかの値を選択することができる。

まとめ

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ドキュメント

この記事をシェアする
  • URLをコピーしました!
  • URLをコピーしました!
目次