4

C# コンパイラがヒープではなくスタックに配列を配置することを決定する場合があることを示唆するブログ エントリを見つけました。

スタック割り当てによるパフォーマンスの向上 (.NET メモリ管理: パート 2)

この男は次のように主張しています。

コンパイラは、独自にスタックに置くことを決定することもあります。私は TestStruct2 で実験を行い、安全でないコンテキストと通常のコンテキストの両方を割り当てました。unsafe コンテキストでは配列はヒープに配置されましたが、通常のコンテキストではメモリを調べたところ、配列は実際にはスタックに割り当てられていました。

誰かがそれを確認できますか?
私は彼の例を繰り返そうとしましたが、試行するたびに配列がヒープに割り当てられました。

C#コンパイラが「unsafe」キーワードを使用せずにそのようなトリックを実行できる場合、私は特に興味があります。多くの小さなバイト配列 (長さ 8 ~ 10 バイト) で動作するコードがあるため、新しいバイトごとに [...] ヒープを使用すると、時間とメモリが無駄になります (特に、ヒープ上の各オブジェクトには 8 バイトのオーバーヘッドがあります)。ガベージ コレクターに必要)。

編集:なぜそれが私にとって重要なのかを説明したいだけです
..netコードを動作させることができるGemalto.NETスマートカードと通信するライブラリを書いています. 何かを返すメソッドを呼び出すと、スマート カードは戻り値の正確なタイプを説明する 8 バイトを返します。この 8 バイトは、md5 ハッシュといくつかのバイト配列連結を使用して計算されます。
問題は、私が知らない配列がある場合、アプリケーションにロードされたすべてのアセンブリのすべての型をスキャンし、同じ配列が見つかるまでそれぞれの 8 バイトを計算する必要があることです。
型を見つける他の方法がわからないので、できるだけ高速化しようとしています。

4

3 に答える 3

4

リンク先の記事の著者はこちら。

安全でないコンテキストの外でスタック割り当てを強制することは不可能のようです。これは、スタックオーバーフロー状態の一部のクラスを防ぐために当てはまる可能性があります。

代わりに、必要に応じてバイト配列を割り当てるだけでなく、後で再利用するために「それらを提出」できるメモリリサイクラークラスを使用することをお勧めします。未使用のバイト配列のスタックを保持し、リストが空の場合は新しいものを割り当てるのと同じくらい簡単です。

Stack<Byte[]> _byteStack = new Stack<Byte[]>();

Byte[] AllocateArray()
{
Byte[] outArray;
if (_byteStack.Count > 0)
  outArray = _byteStack.Pop(); 
else
  outArray = new Byte[8];
return outArray;
}

void RecycleArray(Byte[] inArray)
{
  _byteStack.Push(inArray);
}

ハッシュをタイプと一致させようとしている場合は、高速ルックアップに辞書を使用するのが最善のアイデアのようです。この場合、起動時に関連するすべてのタイプをロードできます。これによりプログラムの起動が遅くなりすぎる場合は、各タイプを初めて使用するときにそれらをキャッシュすることを検討してください。

于 2009-07-17T14:10:37.947 に答える
2

あなたのラインから:

多くの小さなバイト配列(8〜10バイトの長さ)で動作しているコードがあります

個人的には、コードのさまざまな部分を(同じブロックを処理しながら)再利用できる場所にスペアバッファーを割り当てることに興味があります。そうすれば、心配する必要のある作成/GCはありません。ほとんどの場合(バッファが非常に目立たない操作に使用される場合)、スクラッチバッファを使用すると、それが「すべて自分のもの」であると常に想定できます。つまり、それを必要とするすべてのメソッドは、ゼロから書き込みを開始できると想定できます。

私はこのシングルバッファアプローチをいくつかのバイナリシリアル化コードで使用しています(データのエンコード中)。パフォーマンスが大幅に向上します。私の場合、シリアル化のレイヤー間で「コンテキスト」オブジェクトを渡します(これは、スクラッチバッファー、出力ストリーム(いくつかの追加のローカルバッファーを含む)、およびその他のいくつかの奇妙なものをカプセル化します)。

于 2009-07-14T08:00:52.507 に答える
1

System.Array(配列を表すクラス)は参照型であり、ヒープ上に存在します。安全でないコードを使用する場合にのみ、スタックに配列を含めることができます。

あなたが参照している記事のどこにそれが別の言い方をしているのかわかりません。スタックに配列を割り当てたい場合は、次のようにすることができます。

decimal* stackAllocatedDecimals = stackalloc decimal[4];

個人的には気にしませんが、このアプローチでどれだけのパフォーマンスが得られると思いますか?

ただし、このCodeProjectの記事は役立つかもしれません。

于 2009-07-14T07:37:51.977 に答える