いくつかのメモリ集約型プログラム(2〜5 GB)を連続して実行するコマンドを含むシェルスクリプトを実行していました。スクリプトの進行状況を確認するために戻ったとき、端末から報告されたように、プロセスの一部がKilled
であることに驚いた。いくつかのプログラムは、後でKilled
が開始する前に既に連続して完了していましたが、その後すべてのプログラムがセグメンテーションエラーで失敗しました(私のコードのバグが原因であるかどうかに関係なく、読み続けてください)。
私が使用していた特定のクラスターの使用履歴を確認したところ、誰かがメモリを大量に消費するプロセスを同時に実行し始めたところ、クラスターで使用できる実際のメモリ(そして場合によってはスワップ領域も)を使い果たしたことがわかりました。私の知る限りでは、これらのメモリを大量に消費するプロセスは、プログラムで問題が発生し始めるのとほぼ同時に実行され始めました。
Linuxがメモリ不足でプログラムを強制終了した可能性はありますか?そして、後で発生したセグメンテーションエラーは、(コード内のバグではなく)プログラムを実行するために利用できるメモリの不足が原因であった可能性はありますか?
できる。
Linuxで発生する可能性のある2つの異なるメモリ不足状態があります。どちらが発生するかは、sysctl vm.overcommit_memory
(/proc/sys/vm/overcommit_memory
)の値によって異なります。
前書き:
カーネルは、いわゆる「メモリオーバーコミット」を実行できます。これは、カーネルがシステムに実際に存在するよりも多くのメモリをプログラムに割り当てるときです。これは非常に一般的なことなので、プログラムが実際に割り当てたすべてのメモリを使用しないことを期待して行われます。
overcommit_memory
が2
に設定されている場合、カーネルはオーバーコミットをまったく実行しません。代わりに、プログラムにメモリが割り当てられると、そのメモリを使用するアクセスが保証されます。システムに割り当て要求を満たすのに十分な空きメモリがない場合、カーネルは要求に対して失敗を返します。状況を適切に処理するのはプログラム次第です。実際に失敗したときに割り当てが成功したかどうかを確認しないと、アプリケーションでsegfaultが発生することがよくあります。
Segfaultの場合、dmesg
の出力で次のような行が見つかります。
[1962.987529] myapp[3303]: segfault at 0 ip 00400559 sp 5bc7b1b0 error 6 in myapp[400000+1000]
at 0
は、アプリケーションが初期化されていないポインタにアクセスしようとしたことを意味します。これは、メモリ割り当て呼び出しが失敗した結果である可能性があります(ただし、これが唯一の方法ではありません)。
overcommit_memory
を0
または1
に設定すると、オーバーコミットが有効になり、プログラムは実際に利用可能なメモリよりも多くのメモリを割り当てることができます。
ただし、プログラムが割り当てられたメモリを使用したいのに、カーネルがそれを満たすための十分なメモリがないことにカーネルが気付いた場合は、メモリを戻す必要があります。最初に、キャッシュのフラッシュなどのさまざまなメモリクリーンアップタスクを実行しようとしますが、これが十分でない場合は、プロセスを終了します。この終了はOOM-Killerによって実行されます。 OOM-Killerはシステムを調べて、どのプログラムがどのメモリを使用しているか、どのくらいの期間実行しているか、誰が実行しているか、その他のいくつかの要因を確認して、どのプログラムが強制終了されるかを判断します。
プロセスが強制終了されると、使用していたメモリが解放され、メモリ不足状態を引き起こしたプログラムに必要なメモリが確保されます。
ただし、このモードでも、プログラムは割り当て要求を拒否される可能性があります。 overcommit_memory
が0
の場合、カーネルは、割り当て要求の拒否を開始するタイミングを推測します。それが1
に設定されている場合、リクエストを拒否するタイミングを決定するためにどの決定を使用するかわかりませんが、非常に大きなリクエストを拒否する可能性があります。
dmesg
の出力を見て、次のようなメッセージを見つけることにより、OOM-Killerが関係しているかどうかを確認できます。
[11686.043641] Out of memory: Kill process 2603 (flasherav) score 761 or sacrifice child
[11686.043647] Killed process 2603 (flasherav) total-vm:1498536kB, anon-rss:721784kB, file-rss:4228kB
真実は、あなたがそれをどのように見るかに関係なく-システムのメモリマネージャーが原因でプロセスが詰まったかどうかにかかわらず、それはまだバグです。メモリ内で処理していたすべてのデータはどうなりましたか?保存されているはずです。
overcommit_memory=
はLinux OOM管理を構成する最も一般的な方法ですが、次のようにプロセスごとに調整することもできます。
echo [-+][n] >/proc/$pid/oom_adj
上記で-17
を使用すると、プロセスがメモリ不足の管理から除外されます。おそらく一般的には素晴らしいアイデアではありませんが、バグハンティングをしている場合はそうする価値があります。特に、それがOOMであるかどうかを知りたい場合はorコードです。正の数を増やすと、OOMイベントでプロセスが強制終了される可能性が高くなります。これにより、メモリ不足の状況でのコードの復元力を強化し、必要に応じて正常に終了できるようになります。
次のように、プロセスごとにOOMハンドラーの現在の設定を確認できます。
cat /proc/$pid/oom_score
そうでなければ、あなたは自殺することができます:
sysctl vm.panic_on_oom=1
sysctl kernel.panic=X
これにより、メモリ不足が発生した場合にコンピューターが再起動するように設定されます。上記のX
を、カーネルパニック後に再起動する前にコンピューターが停止する秒数に設定します。ワイルドに。
そして、なんらかの理由で気に入った場合は、永続化します。
echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=X" >> /etc/sysctl.conf