web-dev-qa-db-ja.com

Linuxでのメモリのオーバーコミットの目的は何ですか?

私は memory overcommitment について知っており、それを非常に嫌い、通常は無効にします。

適切に作成されたプログラムは、使用可能なメモリよりもmalloc(またはmmapがよく使用するmalloc)のメモリを使用し、使用時にクラッシュする可能性があります。メモリのオーバーコミットメントがなければ、そのmallocまたはmmapは失敗し、適切に記述されたプログラムはその失敗をキャッチします。失敗したmallocの結果を使用すると、不適切に作成されたプログラム(失敗に対するチェックなしでmallocを使用)がクラッシュします。

もちろん 仮想アドレス空間 (これはmmapによって拡張され、mallocによって拡張されます)はRAM(RAMはカーネルによって管理されるリソース。 this を参照してください。プロセスの仮想アドレス空間は execve(2) によって初期化され、mmapsbrkしたがって、直接RAMを消費しないでください 仮想メモリ )のみ。

最適化RAM使用法は madvise(2) で実行できることに注意してください。これは、いくつかのページをスワップするカーネルにMADV_DONTNEEDを使用してヒントを与えることができますディスク))、本当に必要な場合。オーバーコミットを必要とするプログラムは mmap(2) with MAP_NORESERVEを使用できます。メモリのオーバーコミットについての私の理解は、すべてのメモリマッピング(execveまたはmmap)が暗黙的に使用しているMAP_NORESERVE

私の考えでは、非常にバグの多いプログラムに単純に役立つということです。しかし、実際の開発者が常にmallocmmapの失敗、および関連する仮想アドレス空間変更関数(たとえば、 here )のように。そして、私が研究したソースコードを持つほとんどのフリーソフトウェアプログラムは、おそらくいくつかの xmalloc 関数として、そのようなチェックをしています...

実生活プログラムはありますか?通常のLinuxディストリビューションにパッケージ化されており、実際にメモリオーバーコミットメントを必要とし、正常かつ有用な方法で使用していますか?誰も知りません!

メモリのオーバーコミットを無効にすることの欠点は何ですか?多くの古いUnix(例えば、前世紀のSunOS4、SunOS5)にはそれがなく、malloc(そしておそらく一般的なフルシステムパフォーマンスでさえmalloc- wise)はそれほど多くありませんでしたより悪い(そしてそれ以降の改善はメモリのオーバーコミットメントとは無関係です)。

私は、メモリのオーバーコミットメントが怠惰なプログラマーにとっては間違った特徴であると思います。

オーバーコミットの理由は、物理RAMが十分に活用されないようにするためです。プロセスが割り当てた仮想メモリの量と、この仮想メモリのどれが実際に物理ページフレームにマップされたかには、違いがあります。実際、プロセスの開始直後は、RAMをほとんど確保していません。これはデマンドページングが原因です。プロセスには仮想メモリレイアウトがありますが、仮想メモリアドレスから物理ページフレームへのマッピングは、メモリの読み取りまたは書き込みが行われるまで確立されません。

プログラムは通常、仮想メモリ空​​間全体を使用することはなく、プログラムの実行中にタッチされるメモリ領域は変化します。たとえば、実行の開始時にのみ実行される初期化コードを含むページフレームへのマッピングを破棄し、ページフレームを他のマッピングに使用できます。

同じことがデータにも当てはまります。プログラムがmallocを呼び出すと、データを格納するために十分な大きさの連続した仮想アドレス空間が予約されます。ただし、物理ページフレームへのマッピングは、ページが実際に使用されるまで確立されませんもしあれば。または、プログラムスタックを検討してください。すべてのプロセスは、スタック用に確保されたかなり大きな連続した仮想メモリ領域(通常8 MB)を取得します。プロセスは通常、このスタックスペースの一部のみを使用します。小さくて適切な動作をするプログラムは、使用量がさらに少なくなります。

通常、Linuxコンピューターには、その存続期間のさまざまな段階で実行される多くの異種プロセスがあります。統計的には、どの時点でも、割り当てられている(またはプログラム実行の後半で割り当てられる)すべての仮想ページのマッピングをまとめて必要とするわけではありません。

厳密にオーバーコミットしないスキームでは、仮想ページが割り当てられた時点で、仮想アドレスページから物理RAMページフレームへの静的マッピングが作成されます。これにより、多くのRAMページフレームが何も予約されないため、同時に実行できるプログラムの数がはるかに少なくなります。

メモリーのオーバーコミットには危険があり、対処が面倒なメモリー不足の状況につながる可能性があることを否定しません。それはすべて、適切な妥協点を見つけることです。

11
Johan Myréen

あなたは、怠惰がプログラミングでvirtueと見なされないかのようにこれを言います:)。

大量のソフトウェアがシンプルさと保守性のために最適化されており、メモリ不足の状態が非常に低い優先度として存続します。割り当ての失敗を致命的なものとして扱うことは一般的です。メモリを使い果たすプロセスを終了すると、空きメモリがない状況が回避され、システムは、より多くのメモリを割り当てるか、総合的な事前割り当てという形で複雑にしないと処理を進めることができません。

割り当てのチェックと死ぬか、チェックしないとクラッシュするかの違いがどれほど細かいことに注意してください。 malloc()が成功したか失敗したかを確認するだけの煩わしさがないプログラマーに対して、オーバーコミットのせいにするのは公平ではありません。

割り当てが失敗した場合でも、「正しく」続行できると信頼できるソフトウェアはごくわずかです。カーネルは通常、存続することが期待されます。 sqliteには 悪名高いほど堅牢なテスト があります。これは、さまざまな小さな組み込みシステムをサポートすることを目的としているため、メモリ不足のテストを含みます。

通常の操作では使用されない障害パスであるため、メモリ不足の状態を正しく処理すると、保守とテストにかなりの余分な負担がかかります。 その努力が相応の利益をもたらさない場合、他の場所でより有益に費やすことができます

これがうまくいかない場合は、最も一般的な失敗の原因を処理するために、大規模な割り当てを行う特別なケースがあることもよくあります。

特定の量のオーバーコミット を許可することは、おそらくこのコンテキストで見るのが最善です。これは、Linuxにおける現在のデフォルトの妥協の一部です。

カーネルレベルのオーバーコミットを無効にして、代わりにswapを提供する必要があるという考えに注意してください。これにも問題があります。 RAMと回転するハードドライブの間の速度のギャップは時間とともに大きくなり、システムが実際に許可したスワップ領域を使用するとき、それは「停止」。

4
sourcejedi

JohanMyréenの回答に同意して賛成しましたが、ここでは、問題を理解するのに役立つ可能性のある詳細な説明を示します。

スワップ領域を混同しているようです。つまり、使用量の少ないRAMおよび仮想メモリを保存するためのディスク領域です。後者はRAMエリアの組み合わせで構成されています。およびディスク領域。

プロセスは仮想メモリを予約して使用しています。彼らはそれがどこに保存されているのかを知りません。 RAMにないデータにアクセスする必要がある場合、カーネルがデータページを使用できるようにするジョブを実行するまで、プロセス(またはスレッド)は中断されます。

RAM要求がある場合、カーネルはディスクスワップ領域に使用されていないプロセスページを保存することにより、一部のRAM=を解放します。

プロセスがメモリを予約すると(mallocなど)、オーバーコミットしないOSは仮想メモリの未使用部分を使用不可としてマークします。つまり、割り当てを行ったプロセスが実際に予約済みページにアクセスする必要がある場合、それらが存在することが保証されます。

欠点は、メモリが他のプロセスで使用できないという事実により、これらのプロセスのページにページが付けられないため、RAMは、これらのプロセスが非アクティブの場合は無駄になります。最悪の場合、合計予約のサイズがスワップ領域のサイズよりも大きい場合、RAMのページもデータが含まれていなくても予約に一致するように予約されます。これは、 RAMこれは両方使用不可and未使用です。最後に、最悪の場合のシナリオは、巨大な予約が受け入れられないためです。使用可能な仮想メモリ(スワップ+ ram)はもうありません。通常、予約を行うプロセスはクラッシュします。

一方、LinuxなどのOSをオーバーコミットすると、仮想メモリが不足することはありません。それらはほとんどのメモリ予約を受け入れますが(非現実的なものではなく、これは多少調整される可能性があります)、一般に、これによりRAMおよびスワップリソースの使用率が向上します。

これは、航空会社が座席をオーバーブッキングすることに似ています。これにより入居率は向上しますが、一部の乗客は不満を感じるかもしれません。うまくいけば、航空会社はそれらを別のフライトに予約し、Linuxがより重い乗客を飛行飛行機から投げ出す間、それらを補償する可能性があります...

要約すると、他のいくつかのOSが予約を保証しているのに対し、Linuxはレイジーな「ベストエフォート」方式でメモリを予約します。

オーバーコミットが理にかなっている実際のケースのシナリオは、多くの仮想メモリを使用するプログラムがforkを実行し、その後にexecを実行する場合です。

4 GBのRAMから、仮想メモリ用に3 GBと4 GBのスワップが利用可能であるとします。4GBを予約しているプロセスがありますが、そのうち1 GBしか使用していません。オーバーコミットしないOSでは、フォークの直後に4 GB以上の仮想メモリを予約する必要があり、残りは3 GBしかないため、そのプロセスはフォークできません。

Linuxでは、このフォーク(またはクローン)システムコールは正常に完了します(ただし、裏では不正行為)。次のexec(存在する場合)の後、予約されているが未使用の4 GBは何の害もなく解放されます。

3
jlliagre

スパース配列

man proc for /proc/sys/vm/overcommit_memoryは実際にアプリケーションを引用しています。

モード1では、カーネルは実際にメモリが不足するまで、常に十分なメモリがあるように見せかけます。このモードの1つの使用例は、大規模なスパース配列を使用する科学計算アプリケーションです。

これが実際に実際に使用されているかどうかはわかりません。

/proc/sys/vm/overcommit_memoryの詳細: https://stackoverflow.com/questions/2798330/maximum-memory-which-malloc-can-allocate/57687432#57687432