3

私の現在のプロジェクトには植生シミュレーションが含まれており、時間の経過とともに成長および再生する多数のインスタンス化された樹木モデルをレンダリングできます。

現在、このコード行で一貫した OutOfMemory 例外が発生しています

if (treeInstances.Length <= currentIndex)
    Array.Resize(ref treeInstances, currentIndex + 500);

このコードは、シミュレーションが配列の通常の境界を超えたときに実行treeInstancesされ、ツリー用に追加の 500 スロットを持つ新しい配列を割り当てます。

失敗したときの配列のサイズ (通常は 3000 から 5000 のインスタンスの間) とTreeInstance構造体のサイズ (20 個の浮動小数点数) を確認できることを考えると、私の問題は配列の生のサイズにあるのではないと確信しています。resize/8 プロセス中に一時的に 2 倍にする必要があることを考慮しても (Array.Resize()新しい配列を割り当てるため)、私の数学が正しいと仮定すると、まだ半分の MB 未満です。

したがって、私が見逃しているものがあるに違いないと思います。古い配列がガベージ コレクターによって削除されない理由はありますか?

詳細:

  • TreeInstance各ツリーの変換行列と色を含む単純な構造体です。
  • treeInstancesTreeInstance[]配列です。これは、上記のコード行で直接使用されるだけです。
  • treeInstancesTreeInstances経由でアクセスするProperty もあります。get;set;
  • TreeInstancesDraw成長する各ツリーの変換マトリックスと色を設定するために使用され、ルーチン の一部としてインスタンス化メソッドに供給されます。
  • 私はあまりよく知らないインスタンス化メソッドですが、そのTreeInstances内容を変更せずにさまざまな機能を実行します (操作でソースとして使用することを含むDynamicVertexBuffer.SetData)。
4

2 に答える 2

1

C# は、小さなメモリ割り当てを大きなメモリ割り当てよりもはるかに適切に処理するように設計されています。Array.Resize を実行すると、新しいメモリ ブロックが強制的に割り当てられ、データがコピーされてから古いブロックが無効になります。これは、ヒープを断片化するための非常に効果的なアルゴリズムです:-)

最初に配列に必要な大きさがわかっている場合は、配列をそのサイズにします。そうでない場合は、List または同様のクラスを使用することをお勧めします。そのクラスはアイテムごとに割り当てます。

正直に言ってくれてありがとう。私は構造体ではなくクラスを扱うことに慣れすぎています。もっと目覚めるべきだった。

TreeInstance がクラスに変更された場合、List はアドレスの配列になり、TreeInstance はより小さなチャンクで割り当て可能/割り当てられます。すべての TreeInstance を新しくするには、いくつかのコード変更が必要になります。

于 2013-10-25T01:45:05.410 に答える
0

Array.Resize()私のシステムが「ヒープを断片化するための非常に効果的なアルゴリズム」であるというDweeberlyの説明をフォローアップして、私の質問に対する答えを見つけたようです。それは私の側の概念化の問題でした.ガベージコレクションが配列をキャッチしないために何らかの制限に達していると仮定する代わりに、十分な連続メモリがないためにメモリ不足例外が発生する可能性があることを理解していませんでした。

Eric Lippert によるこのブログ投稿は、私を正してくれました。

http://blogs.msdn.com/b/ericlippert/archive/2009/06/08/out-of-memory-does-not-refer-to-physical-memory.aspx

メモリ不足の例外を扱っている人、またはゲーム プログラミングの一般知識として読む価値があります。

簡単な答えは次のとおりです: 32 ビット Windows 用にコンパイルされたプログラムでは、大きなオブジェクトを繰り返し割り当ててから削除すると、割り当ててArray.Resize()いるオブジェクトと同じ大きさの空き領域の「ブロック」にアドレス空間を断片化できます。 . その後、これらの空きブロックよりも大きなオブジェクトを割り当てようとすると、累積メモリがはるかに大きくても、メモリ不足の例外がスローされます。

上で示唆したように、適切な対応は単純に、配列のサイズを繰り返し変更することを避けることです。私の場合、これはインスタンス化モデルのメソッドを書き直して、配列全体ではなく、より大きな配列のサブセットのみを描画することを意味していました。その後、初期化中に必要になるよりもはるかに大きな配列を割り当てる簡単な方法でした。

于 2013-11-04T00:54:52.133 に答える