これには、誰を殺すべきかという質問が含まれます。一般に、Linux カーネルについて少しでも知っている学生は、Linux カーネルを最もよく使用している人にまず反応し、その人を殺します。もちろん、これは Linux カーネルが最初に考慮する重要な要素ですが、完全に当てはまるわけではありません。一部の Linux カーネル情報をチェックすると、実際に誰が強制終了されるかは /proc/
badness() 関数のコメント部分には、 badness() 関数の処理アイデアが記載されています:
1) 最低限の作業量が失われます
2) 大量のメモリを回復します
3) 大量のメモリを消費する無害なものは何も殺しません
4) 最小限のプロセス (1 つ) を強制終了したいです
5) ユーザーが強制終了を期待しているプロセスを強制終了しようとします。このアルゴリズムは、最小驚きの原則を満たすように細心の注意を払って調整されています... (変更する場合は注意してください)
一般に、最大量のメモリを取得するために最小限の数のプロセスを強制終了します。これは、最大量のメモリを占有するプロセスを強制終了することと一致します。
/*
※プロセスのサイズメモリが悪さの根拠です
*/
ポイント = p->mm->total_vm;
スコアの開始点は、プロセスによって実際に使用される RAM メモリです。ここには SWAP が含まれていないことに注意してください。つまり、OOM Killer はプロセスの実際の物理メモリにのみ関連し、スワップとは関係ありません。そして、プロセスによって実際に使用される物理メモリは、メモリが多いほどスコアが高く、スコアが高いほど犠牲になりやすいことがわかります。
/*
* 多くの子プロセスをフォークするプロセスの可能性があります
* 子供の vmsize を追加するのは良い選択です
* 独自の mm を持っています。これにより、フォーク中のサーバーが
にフラッディングするのを防ぎます。
* 無限の数の子供たちがいるマシン
*/
...
If (chld->mm != p->mm && chld->mm)
ポイント += chld->mm->total_vm;
この段落は、子プロセスが占有するメモリが親プロセスに対して計算されることを意味します。
s = int_sqrt(cpu_time);
if (s)
ポイント /= s;
s = int_sqrt(int_sqrt(run_time));
if (s)
ポイント /= s;
これは、プロセスが占有する CPU 時間が長いほど、またはプロセスの実行時間が長いほど、スコアが低くなり、プロセスが強制終了される可能性が低くなることを示しています。
/*
* 優れたプロセスは重要性が低い可能性が高いため、2 倍
* 彼らの悪い点。
*/
If (task_nice(p) > 0)
ポイント *= 2;
プロセスの優先度が低い場合 (適切な値、正の値は優先度が低く、負の値は優先度が高い)、ポイントは 2 倍になります。
/*
* 通常、スーパーユーザープロセスの方が重要なので、それを作成します
* 私たちがそれらを殺す可能性は低くなります。
*/
If (cap_t(p->cap_効果) & CAP_TO_MASK(CAP_SYS_ADMIN) ||
p->uid == 0 || p->euid == 0)
ポイント /= 4;
スーパーユーザーのプロセス優先度は低くなります。
/*
* ハードウェアに直接アクセスしてプロセスを強制終了したくありません。
* それはハードウェアを台無しにするだけでなく、通常はユーザーを台無しにする可能性があります
* このフラグは、彼らが考えるアプリケーションにのみ設定される傾向があります
* * 重要です
*/
If (cap_t(p->cap_Effective) & CAP_TO_MASK(CAP_SYS_RAWIO))
ポイント /= 4;
元のデバイスに直接アクセスできるプロセスの優先度が高くなります。
/*
* oomkilladj でスコアを調整します
*/
If (p->oomkilladj) {
If (p->oomkilladj>0)
ポイント <<= p->oomkilladj;
その他
ポイント >>= -(p->oomkilladj);
}
各プロセスには強制終了するプロセスの優先度を設定できる oomkilladj があり、このパラメータは Point に比較的大きな影響を与えるようです。最大値は +15、最小値は -17 です。この値はモバイル ビット操作であるため、影響は依然として比較的大きいです。
実験用の小さなプログラムを書いてみましょう:
リーリー
上記のプログラムは、最初に 1G のメモリ空間を適用し、次に 100M 単位でメモリ空間を埋めます。上記の 3 つのプロセスを、2G メモリと 400M スワップ領域を備えたマシンで実行します。実行結果を見てみましょう:
Test1、test2、test3 はそれぞれ 1G の仮想メモリ空間 (VIRT) を適用し、その後 10 秒ごとに実際に占有される RAM 空間が 100M (RES) ずつ増加しました。
物理メモリ領域が不足すると、OS がスワップの実行を開始し、利用可能なスワップ領域が減少し始めます。
メモリに割り当てるスペースがない場合、test1 プロセスはオペレーティング システムによって強制終了されます。 dmesg test1 プロセスが OS によって強制終了され、oom_score が 1000 になったことがわかります。
これら 3 つのプロセスの oom_adj はすべてデフォルト値 0 に設定されています。 oom_adj の設定の効果を試してみましょう。 3 つのプロセスを再起動すると、test2 の PID が 12640 であることがわかります
次のステートメントを実行してみましょう
エコー 15 > /proc/12640/oom_adj
しばらくすると、スワップ領域が急激に減少し、基本的に OS OOM_Killer が起動しようとしていることがわかりました。
予想通り、12640 プロセスが強制終了されました。
したがって、必要なプロセスが強制終了されるのを防ぐために、プロセスの oom_adj を設定することでこれを行うことができます。もちろん、これはすべてオーバーブッキングが原因であると言う人もいるでしょう。Linux にはオーバーコミット機能を無効にする overcommit_memory が用意されているのですから、それを無効にすればよいのです。これには利点と欠点があります。これは、MySQL が実際のメモリを超える領域を適用できないことを意味します。アプリケーションが適用できない場合、MySQL はメモリ領域を動的に適用できます。これにより、必要な時間が大幅に増加します。MySQL のダウンタイムのリスクが Linux のオーバーコミットの原因です。
上記の分析により、oom_adj が設定されていない場合、MySQL が一般に最大のメモリを占有するため、一般に MySQL が OOM_Killer の最初の選択肢となることがわかります。では、MySQL として強制終了のリスクを回避するにはどうすればよいでしょうか? 次の章では、MySQL の観点から OOM を回避する方法を分析することに焦点を当てます。