Windows 10 ではメモリ/コミット チャージはどのように機能しますか?

Windows 10 ではメモリ/コミット チャージはどのように機能しますか?

この質問は、私が説明を見つけたいと思っている、定期的に観察される以下の現象から生じています。

  1. 現在のコミットは、物理使用量 + ページファイル サイズよりも定期的に高くなっています。これはどういうことでしょうか。不可能ではないでしょうか。[これは圧縮が原因のようです。これにより、質問は次のように変わります。コミット制限がなぜ上がらないのか、など。つまり、メモリ使用量の削減に役立たないのなら、圧縮の意味は何でしょうか。]
  2. 場合によっては、現在のコミットが物理メモリ使用量の 2 倍を超える極端なレベルに達することもあります。
  3. コミット チャージがいっぱいになり、Windows が何かを閉じるように要求し始めると、ほとんどの場合、物理メモリは約 60% になります。これはひどく非効率に思えます。

これは、Process Explorer によって報告された Windows 10 上のものです。

私が答えたい究極の質問は、物理メモリを実際に効果的に活用するために、スペース不足の SSD が処理できないレベルまでページ ファイルを人工的に膨らませるのをやめることができるかということです。(または、物理メモリがそれほどいっぱいでなくてもかまいません。つまり、「ページ ファイルに X/Y/Z を実行してください」などの提案は避けたいのです。)

答え1

これは、コミット料金が潜在的- ただし、「必要に応じて利用可能であることが保証されている」仮想メモリの使用。一方、「プライベートワーキングセット」は、基本的に「コミットされた」メモリによって使用されるRAMであり、実際の使用頻度は、ページファイル領域と同様です。(ただし、RAM を使用するものは他にもあるため、これが RAM の使用頻度のすべてではありません)。

32ビットシステムの場合、各プロセスで利用可能な仮想アドレス空間の最大サイズは通常2GiBです。(どれでも64 ビット システムの場合は、アドレスとサイズがさらに大きくなることを除いて、次のようになります (はるかに大きくなります)。

ここで、プロセスで実行されているプログラムが VirtualAlloc (Win32 API) を使用して 2 MiB の仮想メモリを「コミット」するとします。予想どおり、これは追加の 2 MiB のコミット チャージとして表示され、将来の割り当てのためにプロセスで使用できる仮想アドレス空間のバイト数が 2 MiB 少なくなります。

しかし、実際にはまだ物理メモリ (RAM) は使用されません。

VirtualAlloc 呼び出しは、割り当てられた領域の開始アドレスを呼び出し元に返します。領域は 0x10000 から 0x7FFEFFFF の範囲、つまり約 2 GiB になります。(各プロセスの VAS の最初と最後の 64KiB、つまり 16 進数で 0x10000 は割り当てられません。)

しかし、2MiBの実際の物理的な使用はありません。ストレージまだです! RAM 内にも、ページファイル内にもありません。(プライベートコミット領域の開始 va と長さを記述する「仮想アドレス記述子」と呼ばれる小さな構造があります。)

というわけで、コミット チャージは増加しましたが、物理メモリの使用量は増加していません。

これは sysinternals ツールを使用して簡単に実証できますtestlimit

しばらくして、プログラムがその領域(場所は問わない)に何か(つまりメモリ書き込み操作)を保存するとします。その領域の下にはまだ物理メモリが存在しないため、このようなアクセスはページフォールトこれに応じて、OS のメモリ マネージャー、具体的にはページ フォールト ハンドラー ルーチン (略して「ページャー」、MmAccessFault と呼ばれます) は次の処理を実行します。

  1. 以前に「利用可能」だった物理ページを割り当てる
  2. アクセスされた仮想ページのページテーブルエントリを設定し、仮想ページ番号を新しく割り当てられた物理ページ番号に関連付けます。
  3. 物理ページをプロセスプライベートに追加するワーキングセット
  4. ページ フォールトを解除し、フォールトを発生させた命令を再試行します。

これで、プロセスに 1 ページ (4 KiB) の「フォールト」が発生しました。それに応じて物理メモリの使用量が増加し、「使用可能な」 RAM が減少します。コミット チャージは変更されません。

しばらくして、そのページがしばらく参照されず、RAM の需要が高くなると、次のようなことが起こる可能性があります。

  1. OS はプロセスのワーキング セットからページを削除します。
  2. ワーキング セットに取り込まれた後に書き込まれたため、変更されたページ リストに配置されます (そうでない場合はスタンバイ ページ リストに配置されます)。ページ テーブル エントリは、RAM のページの物理ページ番号を反映していますが、その「有効」ビットがクリアされているため、次に参照されるとページ フォールトが発生します。
  3. 変更されたページリストが小さなしきい値に達すると、変更されたページライター「システム」プロセス内のスレッドが起動し、変更されたページの内容をページファイルに保存します (ページファイルがある場合)。
  4. これらのページを変更済みリストから削除し、スタンバイ リストに追加します。これらは「使用可能な」 RAM の一部と見なされますが、現時点では、それぞれのプロセスにあったときの元の内容が保持されています。この場合も、コミット チャージは変わりませんが、RAM 使用量とプロセスのプライベート ワーキング セットは減少します。
  5. スタンバイリストのページは、再利用つまり、システム上の任意のプロセスからのページ フォールトを解決したり、SuperFetch によって使用されるなど、他の目的に使用されます。ただし...
  6. 変更済みリストまたはスタンバイ リストにページを失ったプロセスが、物理ページが再利用される前に (つまり、元のコンテンツがまだ残っている前に) 再度そのページにアクセスしようとすると、ディスクから読み取ることなくページ フォールトが解決されます。ページは単にプロセスのワーキング セットに戻され、ページ テーブル エントリは「有効」になります。これは「ソフト」または「安価な」ページ フォールトの例です。スタンバイ リストと変更済みリストは、すぐに再び必要になる可能性のあるページのシステム全体のキャッシュを形成すると言えます。

ページファイルがない場合は、手順 3 ~ 5 は次のように変更されます。

  1. ページの内容を書き込む場所がないため、ページは変更済みリストに残ります。

  2. ページの内容を書き込む場所がないため、ページは変更済みリストに残ります。

  3. ページの内容を書き込む場所がないため、ページは変更済みリストに残ります。

ステップ 6 は同じままです。変更されたリストのページは、「ソフト」ページ フォールトとして、それらを失ったプロセスにフォールトバックされる可能性があるためです。ただし、これが発生しない場合は、プロセスが対応する仮想メモリの割り当てを解除するまで (おそらくプロセスが終了するため)、ページは変更されたリストに残ります。

プライベートコミットメモリ以外にも、仮想アドレス空間やRAMの用途はあります。マップされた仮想アドレス空間。この場合、バッキング ストアはページ ファイルではなく、指定されたファイルです。ページ インされたマップされた vas のページは RAM 使用量に反映されますが、マップされたメモリはコミット チャージに寄与しません。これは、マップされたファイルがバッキング ストアを提供するためです。マップされた領域で RAM にない部分は、マップされたファイルにそのまま保持されます。もう 1 つの違いは、ほとんどのファイル マッピングがプロセス間で共有できることです。あるプロセスのメモリに既にある共有ページは、別のプロセスに追加できます。その場合、ディスクに再度アクセスする必要はありません (別のソフト ページ フォールト)。

そこにはページング不可能vas は常に RAM 内に常駐するため、バッキング ストアはありません。これは、報告される RAM 使用量と「コミット チャージ」の両方に影響します。

これは圧縮が原因のようです。すると、質問は次のように変わります。コミット制限がなぜ上がらないのか、などです。つまり、メモリ使用量の削減に役立たないのなら、圧縮の意味は何でしょうか。

いいえ。圧縮とは何の関係もありません。Windowsのメモリ圧縮は、ページファイルに書き込まれるはずのページに対して中間ステップとして行われます。変更されたページリストより少ないRAMでより多くの情報を保持できます。CPU時間は多少かかりますが、ページファイルI/O(SSDへのI/Oも含む)よりはるかに高速です。コミット制限は合計RAM + ページファイル サイズであり、RAM 使用量 + ページファイル使用量ではありません。これはコミット制限に影響しません。コミット制限は、使用されている RAM の量や使用目的によって変化しません。

コミット チャージがいっぱいになり、Windows が何かを閉じるように要求し始めると、ほとんどの場合、物理メモリは約 60% になります。これはひどく非効率に思えます。

Windows が非効率なわけではありません。実行しているアプリが非効率なのです。アプリは実際に使用しているよりもはるかに多くの VA をコミットしています。

「コミット チャージ」と「コミット リミット」のメカニズム全体の理由は、次のとおりです。VirtualAlloc を呼び出すときに、戻り値がゼロ以外であるかどうかを確認する必要があります。ゼロの場合、割り当ての試行が失敗したことを意味します。これは、コミット チャージがコミット リミットを超える原因となった可能性が高いためです。コミットを減らすか、プログラムを正常に終了するなど、適切な操作を行う必要があります。

VirtualAllocがゼロ以外の値、つまりアドレスを返した場合、システムが保証(つまり約束)したことになります。つまり、そのアドレスから始まるバイト数だけ要求したとしても、だろうアクセスすることを選択した場合に利用可能であること、RAM またはページファイルのいずれかにすべてを配置する場所があること。つまり、その領域内の何かにアクセスする際に何らかの失敗を予想する理由はありません。割り当てられた領域にアクセスするたびに「動作したか?」を確認することを期待するのは合理的ではないため、これは良いことです。

「現金貸付銀行」のアナロジー

これは、銀行が信用を提供するのと少し似ていますが、厳密には手持ちの現金ベースです。(もちろん、これは実際の銀行の仕組みではありません。)

銀行が 100 万ドルの現金を手元に持っているとします。人々は銀行に行き、さまざまな金額の信用枠を要求します。銀行が 10 万ドルの信用枠を承認したとします (プライベートのコミット済み領域を作成します)。これは、現金が実際に金庫から出ていくことを意味しません。後で実際に 2 万ドルのローンを借りると (領域のサブセットにアクセスします)、銀行から現金が削除されます。

しかし、私がローンを借りるかどうかにかかわらず、私が承認された最大10万ドルの融資枠は、銀行がその後、顧客全員に対して合計90万ドル相当の融資枠しか承認できないことを意味します。銀行は現金準備金を超える融資を承認しません(つまり、オーバーコミットなぜなら、銀行は、以前に承認された借り手が後で借り入れをしようとしたときに、その借り手を拒否しなければならない可能性があるからです。彼らのローンを組むことは非常に悪いことです。銀行はすでに関与するそうした融資を許可すると、銀行の評判は急落するだろう。

確かに、これは銀行の現金利用という点では「非効率的」です。そして、顧客が承認された信用枠と実際に貸し出された金額の差が大きいほど、非効率的になります。しかし、その非効率性は銀行のせいではなく、高額の信用枠を要求しながらも少額の融資しか受けない顧客の「せい」なのです。

銀行のビジネスモデルでは、以前に承認された借り手がローンの申し込みに来たときに、その借り手を拒否することはできない。そうすることは、顧客にとって「致命的」となる。そのため、銀行は、ローン資金のうちどれだけが「約束」されているかを注意深く記録している。

ページファイルを拡張したり、別のページファイルを追加したりすることは、銀行が外に出て現金をさらに調達し、それを融資基金に追加するのと同じことだと思います。

このアナロジーでマップされたメモリと非ページング可能メモリをモデル化する場合、非ページング可能メモリは、口座を開設するときに借り入れて保管しておく必要がある小額ローンのようなものです。(各新しいプロセスを定義する非ページング可能構造) マップされたメモリは、自分の現金(マップされているファイル)を持って銀行に預け、一度に一部だけを引き出す(ページインする)ようなものです。一度にすべてをページインしないのはなぜですか? わかりません。財布にその現金をすべて入れる余裕がないのかもしれませんね。:) 預けた現金は自分の口座にあり、一般的なローン資金ではないため、他の人がお金を借りる能力には影響しません。このアナロジーは、特に共有メモリについて考え始めると崩れ始めるので、あまり押し進めないでください。

Windows OSに戻ります。RAMの「利用可能」な容量が十分にあるという事実は、コミットチャージやコミット制限とは関係ありません。コミット制限に近い場合、OSがすでにコミットしていることを意味します。つまり、 提供することを約束した要求されたとき - その量のストレージ。制限を適用するには、まだすべてを使用する必要はありません。

物理メモリを実際に効果的に活用するために、スペース不足の SSD が処理できないレベルまでページ ファイルを人工的に膨らませるのをやめることはできますか? (または、物理メモリがそれほどいっぱいでなくてもかまいません。つまり、「ページ ファイルに X/Y/Z を実行してください」などの提案は避けたいです。)

申し訳ありませんが、コミット制限に達してしまった場合、実行できる方法は 3 つだけです。

  1. RAM を増やしてください。
  2. ページファイルのサイズを増やします。
  3. 一度に実行するものを減らします。

オプション 2 について: 2 番目のページファイルをハード ドライブに置くことができます。アプリが実際にコミットされたメモリをすべて使用していない場合 (空き RAM がたくさんあることから、明らかにそうではないようです)、そのページファイルに実際にアクセスすることはあまりないため、ハード ドライブに置いてもパフォーマンスは低下しません。ハード ドライブの遅さが依然として気になる場合は、別の方法として、小型で安価な 2 番目の SSD を入手し、2 番目のページファイルをそこに置くこともできます。唯一の「致命的な問題」は、2 番目の「非リムーバブル」ドライブを追加する方法がないラップトップです。(Windows では、USB で接続されたドライブなど、リムーバブル ドライブにページファイルを置くことはできません。)

ここは私が書いた別の答えそれは物事を別の方向から説明します。

追伸: Windows 10 について質問されましたが、NT 3.1 に遡るすべての NT ファミリーのバージョン、およびプレリリース バージョンでも同じように動作するということをお伝えしておきます。変更されたと思われるのは、Windows のページファイル サイズのデフォルト設定が、RAM サイズの 1.5 倍または 1 倍から、はるかに小さくなったことです。これは間違いだったと思います。

関連情報