私はカーネル開発者ではありませんが、この問題に何度も遭遇したので、この問題に何年も哲学を費やしました。私は実際に全体の状況の比phorを思いついたので、それを教えてください。私の話では、「スワップ」のようなものは存在しないと仮定します。とにかく、最近の32 GB RAMではスワップはあまり意味がありません。
水がパイプを介して各建物に接続され、町が能力を管理する必要があるあなたの近所を想像してください。1秒間に100単位の水しか生産していないと仮定しましょう(そして、貯水タンクがないため、未使用の容量はすべて無駄になります)。各家(家=小さなアプリ、端末、時計ウィジェットなど)には、1秒間に1ユニットの水が必要です。あなたの人口は90人なので、誰もが十分な水を得ることができるので、これはすべて良いことです。
今、市長(=あなた)は、大きなレストラン(=ブラウザー)を開くことを決定します。このレストランには複数の料理人(=ブラウザータブ)があります。各料理人は毎秒1ユニットの水を必要とします。10人の料理人から始めるので、近所全体の総水消費量は100単位の水であり、それでも十分です。
今、楽しいものが始まります:あなたはレストランに別のコックを雇います。あなたは何かをする必要があります。
水管理(=カーネル)には3つのオプションがあります。
1.最初のオプションは、最近水を使用しなかった家のサービスを単に切断することです。これは問題ありませんが、接続されていない家が再び水を使用したい場合、彼らは再び長い登録プロセスを経る必要があります。管理者は、複数の家を切断して、より多くの水資源を解放できます。実際、彼らは最近水を使用しなかったすべての家の接続を切断し、その結果、ある程度の無料の水を常に利用可能にします。
あなたの町は機能し続けていますが、マイナス面は進歩が止まってしまうことです。あなたの時間のほとんどは、サービスを回復するために水管理を待つことに費やされます。
これは、カーネルがファイルバックアップページで行うことです。大きな実行可能ファイル(クロムなど)を実行すると、そのファイルがメモリにコピーされます。メモリが少ない場合、または最近アクセスされていない部分がある場合、カーネルはそれらをディスクからリロードできるため、それらの部分をドロップできます。これが過度に行われると、すべてがディスクIOを待機するため、デスクトップが停止します。また、多くのIOを実行し始めると、カーネルは最近使用したページの多くをドロップします。これが、DVDイメージのようないくつかの大きなファイルをコピーした後、バックグラウンドアプリに切り替えるのに時間がかかる理由です。
これは私にとって最も厄介な動作です。なぜなら、私は接続を嫌い、あなたはそれを制御することができないからです。スイッチをオフにできると便利です。私はの線に沿って何かを考えています
sed -i 's/may_unmap = 1/may_unmap = (vm_swappiness >= 0)/' mm/vmscan.c
そして、vm_swappinessを-1に設定してこれを無効にすることができます。これは私の小さなテストでは非常にうまくいきましたが、残念ながら私はカーネル開発者ではないので、誰にも送信しませんでした(そして明らかに、上記の小さな変更は完全ではありません)。
2。管理者は、新しい料理人の水に対する要求を拒否する可能性があります。これは最初は良いアイデアのように聞こえます。ただし、2つの欠点があります。まず、それらを使用していないにもかかわらず、多くの水契約を要求する会社があります。これを行う1つの考えられる理由は、余分な水が必要な場合に水管理者と話をするオーバーヘッドをすべて回避することです。彼らの水の使用量は、一日の時間に応じて上下します。たとえば、レストランの場合、会社は真夜中に比べて正午にずっと多くの水を必要とします。したがって、彼らは使用する可能性のあるすべての水を要求しますが、それは深夜に水配分を無駄にします。問題は、すべての企業がピーク時の使用量を正確に予測できるわけではないため、より多くの要求を心配する必要がなくなることを期待して、はるかに多くを要求することです。
これは、Javaの仮想マシンが行うことです。起動時に大量のメモリを割り当て、それから動作します。デフォルトでは、カーネルは、Javaアプリが実際に使用を開始したときにのみメモリを割り当てます。ただし、オーバーコミットを無効にすると、カーネルは予約を真剣に受け止めます。実際にリソースを持っている場合にのみ、割り当てが成功します。
ただし、このアプローチにはもう1つ、より深刻な問題があります。ある会社が毎日10単位ではなく、1ユニットの水を要求し始めたとします。最終的には、空きユニットが0の状態になります。これで、この会社はこれ以上割り当てることができなくなります。とにかく大企業を気にする人は大丈夫です。しかし問題は、小さな家でもより多くの水を要求できないことです!突然の観光客の流入に対処するために、小さな公衆トイレを建設することはできません。近くの森林の火災に緊急用の水を提供することはできません。
コンピューター用語:オーバーコミットのない非常に低いメモリの状況では、新しいxtermを開くことができず、マシンにsshすることも、検索するための新しいタブを開くこともできません修正。つまり、オーバーコミットを無効にすると、メモリ不足のときにデスクトップが使用できなくなります。
3.ここで、企業が水を使いすぎたときに問題を処理する興味深い方法を紹介します。水管理はそれを爆破します!文字通り:レストランのサイトに行き、ダイナマイトを投げ入れ、爆発するまで待ちます。これにより、町の必要水量が一気に減り、新しい人が入居できるようになり、公衆トイレなどを作ることができます。たとえば、すでに多くの人が入っている場合はレストランに行かないように人々に伝えます(たとえば、ブラウザのタブを少なくします)。
これは実際、カーネルがすべてのオプションを使い果たしたときにカーネルが行うことであり、メモリが必要です。OOMキラーを呼び出します。(多くのヒューリスティックに基づいて)大規模なアプリケーションを選択して強制終了し、大量のメモリを解放しますが、応答性の高いデスクトップを維持します。実際、Androidカーネルはこれをさらに積極的に実行します。メモリが少ないときに、最後に使用したアプリを強制終了します(最後の手段としてのみ行うストックカーネルと比較して)。これは、Androidではバイキングキラーと呼ばれます。
これは問題に対する最も簡単な解決策の1つだと思います。これより多くの選択肢があるわけではないので、すぐに解決してください。問題は、OOMキラーの呼び出しを回避するためにカーネルが非常に多くの作業を行う場合があることです。そのため、デスクトップが非常に遅く、カーネルがそれについて何もしていないことがわかります。しかし、幸いなことに、OOMキラーを自分で呼び出すオプションがあります!まず、マジックsysrqキーが有効になっていることを確認し(例echo 1 | sudo tee
/proc/sys/kernel/sysrq
)、カーネルのメモリが不足していると感じたら、Alt + SysRQ、Alt + fを押します。
それでいいのですが、試してみたいですか?メモリ不足の状況は再現が非常に簡単です。そのための非常にシンプルなアプリがあります。2回実行する必要があります。最初の実行で、使用可能なRAMの量が決まり、2回目の実行でメモリ不足の状況が発生します。このメソッドは、スワップが無効になっていることを前提としていることに注意してください(例:を実行sudo swapoff -a
)。コードと使用法は次のとおりです。
// gcc -std=c99 -Wall -Wextra -Werror -g -o eatmem eatmem.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char** argv)
{
int limit = 123456789;
if (argc >= 2) {
limit = atoi(argv[1]);
}
setbuf(stdout, NULL);
for (int i = 1; i <= limit; i++) {
memset(malloc(1 << 20), 1, 1 << 20);
printf("\rAllocated %5d MiB.", i);
}
sleep(10000);
return 0;
}
そして、これがあなたの使い方です:
$ gcc -std=c99 -Wall -Wextra -Werror -g -o eatmem eatmem.c
$ ./eatmem
Allocated 31118 MiB.Killed
$ ./eatmem 31110
Allocated 31110 MiB.Killed
最初の呼び出しは、31,118 MiBの空きRAMがあることを検出しました。そこで、カーネルがメモリを殺すのではなく、ほぼすべてのメモリを使い果たすように、31,110 MiB RAMを割り当てるようアプリケーションに指示しました。私のシステムがフリーズした:マウスポインターでさえ動かなかった。Alt + SysRQ、Alt + fを押すと、eatmemプロセスが強制終了され、システムが復元されました。
メモリ不足の状況で行うオプションを説明しましたが、最善のアプローチは(他の危険な状況と同様に)そもそも回避することです。これを行うには多くの方法があります。私が見た一般的な方法の1つは、システムの残りの部分とは異なるコンテナーに(ブラウザーなどの)動作不良のアプリケーションを配置することです。その場合、ブラウザはデスクトップに影響を与えることはできません。しかし、予防自体は質問の範囲外であるため、これについては説明しません。
TL; DR:現在、ページングを完全に回避する方法はありませんが、オーバーコミットを無効にすることで完全なシステム停止を緩和できます。ただし、メモリ不足の状況ではシステムは使用できませんが、方法は異なります。上記に関係なく、メモリ不足の状況では、Alt + SysRQ、Alt + fを押して、カーネルが選択する大きなプロセスを強制終了します。システムは数秒後に応答性を回復するはずです。これは、マジックsysrqキーが有効になっていることを前提としています(デフォルトでは無効です)。