0

質問する前に、ちょっとした免責事項を述べておきます。はい、仮想メモリ、物理メモリ、およびワーキング セットの違いを認識しています。以下のすべての数字は、仮想メモリを指します。

状況は次のとおりです。x86 C++ ライブラリをインポートする 32 ビット C# アプリがあります (多くのネイティブ依存関係があるため、x64 への移行は現時点ではオプションではありません)。アプリはアンマネージ コンポーネントを介して大規模なデータセットを読み込み、それを表示 (レポート) しようとします。

ただし、データセットが特に大きい場合、以下のコードのように、項目をリストに追加すると OutOfMemory 例外がスローされます。

ここで驚きはありません。ただし、驚くべきことは、アプリケーションがまだ約 280MB の空き VM を持っているという事実です。

純粋なアンマネージ アプリ (C++) をデバッグする場合は、そうではありませんでした。bad_alloc は、空き VM が残っていない場合、または十分なサイズの空きアドレス空間チャンクがない場合にのみ達成できました。

したがって、質問 - これの理由は何ですか? この問題に対処する方法は理解しています。管理されていないコンポーネントは実際に大量のメモリを消費し、多くの断片化を作成します。しかし、OutOfMemoryException が非常に早く表示される理由は何ですか?

問題のコードは次のようになります。

List<Cell> r = new List<Cell>(cols);
for (int j = 0; j < cols; j++)
{
    r.Add(new CustomCell()); // The exception is thrown on this line
}

例外が発生した時点で、リストには 85 個の項目があり、その容量は 200 程度 (コンストラクターで示される列の数) でした。そのため、例外は CustomCell の割り当てで発生した可能性が最も高いです。CustomCell オブジェクトには多くのフィールドがありますが、確かに合計で 1KB 未満です。280MB の空きメモリは 64KB から 14MB のチャンクに配置されているため、割り当てるには十分なスペースがあるはずです。

4

3 に答える 3

0

64 ビット アプリケーションを使用している場合も注意が必要です。レポート テーブルを配列にロードする場合は、配列の最大サイズが 2 GB であることを確認してください。

詳細: 大きな配列の宣言に関する OutOfMemoryException

これもあなたにとって興味深いかもしれません: 2-gb-without-using-jagged-arrays-

于 2013-09-05T14:37:31.980 に答える
0

編集

コードを追加する前に書かれています。あなたはすでにこれをやっているようです:

Listインスタンスには容量があります。容量を超えると、リストの容量を 2 倍にする成長アルゴリズムが呼び出されます。

//decompiled from List<T>
private void EnsureCapacity(int min)
{
  if (this._items.Length >= min)
    return;
  int num = this._items.Length == 0 ? 4 : this._items.Length * 2;
  if ((uint) num > 2146435071U)
    num = 2146435071;
  if (num < min)
    num = min;
  this.Capacity = num; //causes a copying of src array to a new array
}

これにより、予期しないメモリ割り当てが発生する可能性があります。リストの最終的なサイズを予測できる場合は、事前に割り当てて、倍増を回避します。

var myList = new List<SomeType>(expectedCapacity)

于 2013-09-05T14:36:24.683 に答える