12

メモリ制限について読みました

ストリーミングが必要な巨大な画像を処理するアプリケーションがあります。単一フレームのビデオ処理のように。アプリケーションには約40個のプラグインがあり、それぞれにデータベース、画像処理、およびWPFGUIを含めることができます。

このアプリケーションには、古いDotNetWinformsを使用する2つのプラグインもあります。

アプリケーションがRAMで約1.2GBを超えることを除いて、すべてが正常に機能します。次に、新しいメモリが割り当てられているプラ​​グインの異常な場所で、「メモリ不足の例外」が発生します。

私は32ビットとしてコンパイルされた64ビットシステムに取り組んでいます。何をすべきか、どのように障害を検索するかがわかりません。

制限はありますか、それとも捕まえられますか?

4

3 に答える 3

20

使用可能なすべての仮想メモリ空​​間を消費する32ビットプログラムを作成することは非常に困難です。2ギガバイトをはるかに下回る壁にぶつかります。最初に不足するのは、要求されたサイズに収まるのに十分な大きさの仮想メモリのチャンクです。穴に収まるほど小さい割り当てを行うことによってのみ、2GBの制限に達することができます。

その壁は、ビットマップを操作するプログラムの早い段階でヒットします。それらはビットマップピクセルを格納するためにVMの大きなチャンクを消費する可能性があり、それは連続した割り当てである必要があります。それらは、arrayではなく、に格納されtreeます。これは管理されていないメモリ割り当てであり、一般的な.NETメモリプロファイラは問題を示すのに少し役に立たない傾向があります。

アドレス空間の断片化についてできる合理的なことは何もありません。利用可能なすべてのVMを消費できるはずだという考えは間違っています。ビルド後のイベントeditbin.exeで実行し、そのコマンドラインオプションを使用することで、64ビットオペレーティングシステムでより多くの呼吸スペースを確保できます。これにより、プロセスで使用可能な4ギガバイトのVMを使用できるようになります。これは、64ビットバージョンのWindowsに固有のオプションであり、Windowsは上位2GBを必要としないため可能です。そしてもちろん、プラットフォームターゲットをAnyCPUに変更することは、仮想メモリの塊を取得するための迅速かつ簡単な方法です。/LARGEADDRESSAWARE

于 2012-06-08T13:37:41.083 に答える
0

より決定論的になるために、あなたはあなたの記憶がどこに行き着くかをチェックするためにいくつかの統合テストを書くべきです。これで、 WMemoryProfilerを使用して実行できます。最初に1500x1500サイズの画像をロードし、すべてをクリーンアップしてから、すべてのオブジェクトを既知としてマークします。次に、大きな画像を再配置して、どの新しいオブジェクトが割り当てられたかを確認し、それらのオブジェクトがいくつあり、誰がそれらを所有しているかを鋭く確認します。

あなたは、多くの外部モジュールが使用されていると言います。おそらく、メモリの不適切な使用のためにそれらのいくつかを削除し、それらをより良いものに置き換える必要があります。これで確認できます。

制限に達した場合でもIEnumerable<Image>、プロバイダーが画像をロードするタイミングや、画像をキャッシュに保持する期間を決定できる場所など、プラグインがレイジー構造をサポートしている場合は、一部の画像をアンロードしてオンデマンドでロードできます。一部のメモリを解放するために参照を削除します。

[Test]
public void InstanceTracking()
{
   using (var dumper = new MemoryDumper())  // if you have problems use to see the debugger windows true,true))
   {
      TestWith1500x1500();
      dumper.MarkCurrentObjects();
      TestWith3000x3000();
      ILookup<Type, object> newObjects = dumper.GetNewObjects()
                                               .ToLookup( x => x.GetType() );

      // here we do find out which objects are holding most of the memory
      MemoryStatistics statOld = dumper.GetMemoryStatistics();
      foreach (var typeInfo in statOld.ManagedHeapStats
                                   .OrderByDescending(x => x.Value.Count))
      {
            Console.WriteLine("Type {0} has {1} instances of total size {2:N0} bytes", 
                           typeInfo.Key, 
                           typeInfo.Value.Count,
                           typeInfo.Value.TotalSize);
      }

      // then check with the info from above who is holding the most interesting new objects. 
      Console.WriteLine("New Strings:"); // just an example perhaps you should have a look at the images.
      foreach (var newStr in newObjects[typeof(string)] )
      {
          Console.WriteLine("Str: {0}", newStr);
      }
   }
}
于 2012-06-24T07:40:59.707 に答える
0

Windowsで実行されている32ビットアプリケーション(OSが64ビットの場合でも)には4Gbアドレス空間がありますが、これは2Gbアプリケーション/ 2Gbシステムに分割されます(これは別の起動スイッチで3/1に変更できます)。

使用しているメモリの合計が実際には1.2Gbではなく2Gbである可能性が非常に高いですが、この1.2Gbの数値をどのように決定していますか? Process Explorerツールを使用してアプリケーションを確認しましたか?

アプリケーションをANYCPUまたは64ビットに変更すると、64ビットOSではこの制限がなくなる(非常に大きな値に移行する)ことがわかります。

于 2012-06-08T13:18:32.257 に答える