2

私は2GBのようなサイズのアレイを持っています(オーディオサンプルでいっぱいです)。次に、その配列にフィルターを適用します。このフィルターは、入力ソースよりも50%多くのサンプルを生成しています。そこで、サイズが3GBの新しいアレイを作成する必要があります。今、私は5GBのメモリを使用しました。ただし、このフィルターがそのソース配列でのみ動作でき、この配列にさらにスペースが必要な場合。質問:2番目のメモリブロックを作成せずにサイズを変更して、最初のメモリブロックを削除できるメモリをC#で割り当てることはできますか?PCのメモリが4kBページ(またはそれ以上)に分割されているとしたら、なぜC#はその優れた機能を使用できない(?)のでしょうか。

4

2 に答える 2

3

質問:2番目のメモリブロックを作成せずにサイズを変更して、最初のメモリブロックを削除できるメモリをC#で割り当てることはできますか?

いいえ、.NETでアレイのサイズを変更することはできません。配列のサイズを大きくしたい場合は、新しくより大きな配列を作成し、既存の配列から新しい配列にすべてのデータをコピーする必要があります。

この問題を回避するには、メモリの小さなチャンクを割り当て、それをデータの1つの大きなバッファとして提示することに基づいて、独自の「配列」実装を提供できます。この例はStringBuilder、文字のチャンクの実装に基づいており、各チャンクは個別のChar[]配列です。

もう1つのオプションは、P / Invokeを使用して、メモリのページを事前に予約できるVirtualAllocなどの低レベルのメモリ管理機能にアクセスすることです。32ビットプロセスの仮想アドレス空間はわずか4GBであるため、64ビットプロセスでこれを行う必要があります。おそらく、安全でないコードとポインタを操作する必要もあります。

于 2012-08-07T08:58:49.727 に答える
3

フィルタがインプレースで機能する場合は、最初に50%多くのスペースを割り当ててください。知っておく必要があるのは、元のサンプルの実際の長さだけです。

そのコードが常に機能するとは限らず、事前にメモリを消費したくない場合は、元の配列(拡張配列)の半分を割り当てて、アクセスがどの部分に関連しているかを確認できます。

byte[] myOriginalArray = new byte[2GB]; // previously allocated 

byte[] myExtensionArray = new byte[1GB]; // 50% of the original
for(... my processing code of the array ...)
{
  byte value = read(index);
  ... process the index and the value here
  store(index, value);
}

byte read(int index)
{
  if(index < 2GB) return myOriginalArray[index];
  return myExtensionArray[index - 2GB];
}

void store(int index, byte value)
{
   if(index < 2GB) myOriginalArray[index] = value;
   myExtensionArray[index - 2GB] = value;
}

配列へのアクセスごとに、インデックスチェックと減算のオーバーヘッドを追加します。場合によっては、これをよりスマートにすることもできます。たとえば、拡張機能にアクセスする必要がない部分については、より高速なループを使用でき、拡張機能部分に書き込む必要がある部分については、より低速なバージョン(2つの連続したループ)を使用できます。

于 2012-08-07T09:06:32.590 に答える