5

基本的に非常に大きな配列で動作する C++ プログラムを作成しています。Windows では、VirtualAlloc を使用してメモリを配列に割り当てています。これで、VirutalAlloc を使用してメモリを予約することとコミットすることの違いを完全に理解できました。ただし、メモリをページごとに予約領域にコミットすることに利点があるかどうかは疑問です。特に、MSDN ( http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx ) には、MEM_COMMIT オプションに関する次の説明が含まれています。

仮想アドレスが実際にアクセスされない限り、または実際にアクセスされるまで、実際の物理ページは割り当てられません。

私の実験では、これが確認されています。プロセスのメモリ使用量を増やすことなく、数 GB のメモリを予約してコミットできます (タスク マネージャーに表示されるように)。実際のメモリは、実際にメモリにアクセスしたときにのみ割り当てられます。

ここで、アドレス空間の大部分を予約してから、メモリをページごとに (またはアプリのロジックによってはより大きなブロックで) コミットする必要があると主張する例をかなり見てきました。ただし、上で説明したように、メモリはアクセスする前にコミットされているようには見えません。したがって、ページごとにメモリをコミットすることに実際の利点があるかどうか疑問に思っています。実際、メモリをページごとにコミットすると、実際にメモリをコミットするための多くのシステム コールが原因で、実際にはプログラムの速度が低下する可能性があります。領域全体を一度にコミットすると、システム コール 1 回分の料金が発生しますが、カーネルは、実際に使用するメモリのみを実際に割り当てるのに十分なほど賢いようです。

どちらの戦略が優れているかを誰かが説明してくれれば幸いです。

4

1 に答える 1

7

違いは、commit がページ ファイルに対してメモリを「バックアップ」することです。例を挙げると:

  1. 2GB の物理 RAM と 2GB のスワップがあるとします (この目的では、固定サイズのスワップを想定しています)。
  2. 6GB を予約 - OK。
  3. 最初の 2GB をコミットします - OK。
  4. 残りの 4GB をコミットします - 失敗します。
  5. スワップファイルを 8GB に拡張
  6. 残りの 4GB をコミット - 成功。

MEM_COMMIT を使用する主な理由は、実行時エラーの抑制 (アプリの安定性) です。オンデマンドでページをコミットするプロセスがある場合、利用可能なメモリとスワップの量を超えると途中でコミットが失敗する可能性が常にあります。メモリがページ ファイルによってバックアップされている場合、メモリを解放する時点までメモリを使用できるという強力な保証が得られます。

いずれかの方法を選択する理由はいくつかありますが、どちらを選択するかを決定するための完全な科学はないと思います。MEM_RESERVE だけが必要になるのは、非常に大規模なスパース配列のシナリオの場合のみです。例: 使用率が最大で 25 ~ 33% のマルチギガバイト配列 (ハッシュ テーブルを高速化するための一般的な手法など)。

他のほとんどすべては、おそらくどちらの方法でも実行できる灰色の領域です。MEM_COMMIT を前もって使用すると、独自のアプリがもう少し安定し、本質的に、オンデマンドで割り当てる可能性のある競合アプリよりも物理 RAM が優先されます。(最初にRAMを取得すると、物理メモリが使い果たされたときにアプリが最後に残ります)同時に、実際にすべてのRAMを使用していない場合は、マルチタスクの可能性を制限することになります.クライアントのマシンに負荷をかけたり、増大するページ ファイルを介して不必要に無駄なディスク領域を引き起こしたりします。

于 2012-12-23T23:50:13.703 に答える