1

Windows 7 モードで x86 で実行した場合にのみメモリ不足になる .NET アプリケーションがありますが、次の例外があります。

8/4/2013 11:36:52 AM: Main application context(1) CriticalError:    Exception in Application context Run: Main application context : Parameter is not valid.   at System.Drawing.Image.get_Width()
   at System.Drawing.Image.get_Size()
   at DevExpress.XtraBars.BarItem.IsSameSize(Image old, Image newImage)
   at DevExpress.XtraBars.BarItem.set_Glyph(Image value)
   at NordicIT.Mark5.Module.DM.Editor.frmEditorRibbon..ctor()
   at NordicIT.Mark5.Module.DM.Editor.frmEditorRibbon..ctor(IEditFormForBOOptions editFormForBOOptions)
   at NordicIT.Mark5.Module.DM.Actions.TDMActions.<>c__DisplayClass19.<_DocumentTransmitProcess>b__17()
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)

メモリ消費量は約 400 mb で、GDI オブジェクトは約 1500 を消​​費しました (レジストリでこれらの制限を増やしたので、約 10000 まで問題ありません)。

x86 の Windows Server 2008 R2 で同じアプリケーションを実行しても問題はありません (Windows 7 と同じカーネルが必要です)。x86 の Windows XP でも問題ありません。

最大 2 GB のメモリを使用しても、x64 モードで例外が発生することはありません。

私が到達しているメモリの限界を理解するのを手伝ってください。

4

1 に答える 1

8

GDI+ 例外は、.NET が登場するずっと前に開発され、エラー コードがわずかしかないため、かなり貧弱です。このような場合、実際にはメモリに問題がある可能性が非常に高くなります。「パラメーターが無効です」は、イメージを読み込めない理由での GDI+ パントです。これ、イメージ ファイルに不要なファイルが含まれているために、大量のメモリを割り当てようとする可能性があります。膨大な数のケースで選択が不十分です。

32 ビット プロセスには、マシンの RAM の量に関係なく、2 ギガバイトの仮想メモリがあります。アドレス空間は、コードとデータで共有する必要があります。そのチャンクは、CLR、ジッター、フレームワーク アセンブリ、アセンブリ、プログラムのジッター コード、および GC ヒープを含む .NET プログラムが使用する約 10 個の異なるヒープによって占有されます。これらのチャンクの割り当ては、アドレス空間全体に分散する傾向があります。メモリを割り当てると、これらの既存のチャンク間の利用可能な穴から別のチャンクを取得します。

ビットマップの大きな問題は、ビットマップが非常に大きくなる可能性があることです。そして、それらは利用可能な穴の中に収まる必要があります。これらの穴は、プログラムがメモリを割り当てて解放するにつれて、時間の経過とともに小さくなる傾向があります。「アドレス空間の断片化」と呼ばれる問題。通常、プログラムを最初に起動したときに、最大 650 メガバイトのホールを見つけることができます。しかし、プログラムがしばらく実行されていると、そこから急速に低下します。長時間実行されるプログラムの危険ゾーンは、約 90 メガバイトです。ギブ オア テイクです。

ビットマップに収まる十分な大きさの穴が利用できない場合、プログラムはこの例外で爆発します。これは、プログラムが使用可能なすべての仮想メモリを消費するずっと前に発生します。多数の小さな割り当てを行うことはできますが、1 つの大きな割り当てを行うことはできません。

この問題を簡単に解決する方法はありません。1つを除いて。EXE プロジェクトのターゲット プラットフォーム設定を AnyCPU に変更し、VS2012 以降では [32 ビットを優先] をオフにします。64 ビット オペレーティング システムでは、プログラムのVM アドレス空間ははるかに大きく、テラバイトが可能です。十分な大きさの穴を使い果たすことはできません。32 ビット プロセスに固執している場合の難しい解決策は、別のプロセスを使用してビットマップをロードすることです。これにより、さらに 2 ギガバイトのクリーンなアドレス空間を購入できます。多くの場合、実用的ではありません。

SysInternals の VMMap ユーティリティを使用して、プログラムの VM の使用状況を把握できます。大きな穴が 2 つの小さな穴に分かれている、非常に厄介なアドレスに読み込まれた DLL が見つかる場合があります。しかし、期待を膨らませないでください。最初はデータに完全に溺れてしまう傾向があります。

于 2013-08-04T14:19:47.993 に答える