このメソッドが正しく機能していることを信頼できます。250 メガバイトを要求すると、この例外は 32 ビット プロセスでトリップする可能性が非常に高くなります。プログラムがしばらく実行されていると、それを取得するのが難しくなります。
使用可能なすべての仮想メモリ アドレス空間を消費したため、プログラムが OOM でクラッシュすることはありません。割り当てに十分な大きさの穴がアドレス空間に残っていないため、クラッシュします。あなたのコードは、一気に 250 メガバイトを割り当てるのに十分な大きさのホールを要求します。例外が発生しない場合は、この割り当てが失敗しないことを確認できます。
しかし、250 メガバイトはかなり多く、これは非常に大きな配列です。また、「アドレス空間の断片化」と呼ばれる問題が原因で失敗する可能性が非常に高くなります。つまり、プログラムは通常、いくつかの非常に大きな穴 (最大で約 600 メガバイト) から始まります。.NET ランタイムとアンマネージ Windows DLL によって使用されるコードとデータを格納するために行われた割り当ての間に利用可能なホール。プログラムがより多くのメモリを割り当てると、これらの穴は小さくなります。いくらかのメモリを解放する可能性がありますが、それは大きな穴を再現しません. 通常、元のサイズの約半分の2 つの穴があり、元の大きな穴を 2 つに分割する中央のどこかに割り当てられます。
これはフラグメンテーションと呼ばれます。多くのメモリを割り当てて解放する 32 ビット プロセスは、最終的に仮想メモリ アドレス空間を断片化するため、しばらくすると利用可能な最大のホールが小さくなり、約 90 メガバイトがかなり一般的です。250 メガバイトを要求すると、ほぼ確実に失敗します。より低い目標を設定する必要があります。
250 メガバイトまでの割り当ての合計が確実に機能することが保証されているため、別の方法で機能することを期待していたことは間違いありません。ただし、これは MemoryFailPoint がどのように機能するかではなく、可能な限り最大の割り当てをチェックするだけです。言うまでもなく、これはあまり役に立ちません。それ以外の場合は、.NET フレームワークのプログラマーに同情します。私たちが望むように動作させるには費用がかかり、割り当てのサイズが最も重要であるため、実際には保証を提供できません。
仮想メモリは、信じられないほど安価な豊富なリソースです。しかし、それをすべて消費することに近づくのは非常に面倒です。ギガバイトを消費すると、OOM がランダムにストライクする可能性が高くなり始めます。この問題の簡単な修正を忘れないでください。64 ビットのオペレーティング システムを実行しています。したがって、EXE プラットフォーム ターゲットを AnyCPU に変更するだけで、大量の仮想アドレス空間が得られます。OS のエディションによって異なりますが、1 テラバイトが可能です。まだ断片化していますが、もう気にする必要はありません。穴は巨大です。
最後になりましたが、コメントに表示されているように、この問題はRAM とは何の関係もありません。仮想メモリは、使用している RAM の量とはまったく関係ありません。仮想メモリ アドレスを RAM 内の物理アドレスにマップするのは、オペレーティング システムの仕事であり、動的に行われます。メモリの場所にアクセスすると、ページ フォールトが発生する可能性があり、OS がそのページに RAM を割り当てます。逆に、OS はページの RAM を別の場所で必要なときにマップ解除します。RAM が不足することは決してありません。それが発生する前に、マシンの速度が遅くなります。SysInternals の VMMap ユーティリティは、プログラムの仮想アドレス空間がどのように見えるかを確認するのに役立ちますが、大規模なプロセスの情報に夢中になる傾向があります。