C#でプログラミング中に誰かが実際にstackalloc
を使用したことがありますか?私はそれが何をするのか知っていますが、それが私のコードに現れるのは偶然だけです。なぜなら、たとえばstatic
と入力し始めるとIntellisenseがそれを提案するからです。
stackalloc
の使用シナリオとは関係ありませんが、実際にはアプリでかなりの量のレガシー相互運用を行っているため、ときどきunsafe
コードを使用することができます。それにもかかわらず、私は通常unsafe
を完全に回避する方法を見つけます。
そして、.Netの単一スレッドのスタックサイズは〜1Mb(間違っている場合は修正してください)なので、stackalloc
を使用することからさらに予約されています。
「これが私にとって安全でない状態になり、stackalloc
を使用するための正確な量のデータと処理です」と言える実用的なケースはありますか?
stackalloc
を使用する唯一の理由は、パフォーマンス(計算または相互運用性)です。ヒープに割り当てられた配列の代わりにstackalloc
を使用することにより、GCのプレッシャーが少なくなり(GCの実行が少なくて済みます)、配列を固定する必要がなく、ヒープ配列よりも速く割り当てられます。メソッドの終了時に自動的に解放されます(ヒープに割り当てられた配列は、GCの実行時にのみ解放されます)。また、ネイティブアロケータ(mallocまたは.Netに相当するもの)の代わりにstackalloc
を使用することにより、スコープ終了時の速度と自動割り当て解除も得られます。
パフォーマンスに関しては、stackalloc
を使用すると、データの局所性によりCPUでキャッシュヒットする可能性が大幅に増加します。
Stackallocを使用して、[ほぼ]リアルタイムのDSP作業用のバッファーを割り当てました。これは、パフォーマンスを可能な限り一貫させる必要がある非常に特殊なケースでした。一貫性と全体的なスループットには違いがあることに注意してください。この場合、プログラムのその時点でのガベージコレクションの非決定性だけで、ヒープ割り当てが遅すぎることは心配していませんでした。 99%のケースでは使用しません。
stackalloc
は、安全でないコードにのみ関係します。マネージコードの場合、データを割り当てる場所を決定できません。値タイプはデフォルトでスタックに割り当てられます(参照タイプの一部である場合を除き、その場合はヒープに割り当てられます)。参照タイプはヒープに割り当てられます。
プレーンVanilla .NETアプリケーションのデフォルトのスタックサイズは1 MBですが、これはPEヘッダーで変更できます。スレッドを明示的に開始する場合は、コンストラクターのオーバーロードを介して異なるサイズを設定することもできます。 ASP.NETアプリケーションの場合、デフォルトのスタックサイズは256Kのみです。これは、2つの環境を切り替える場合に留意する必要のあることです。
スパンのStackalloc初期化。 C#の以前のバージョンでは、stackallocの結果はポインターローカル変数にのみ保存できました。 C#7.2の時点で、stackallocは式の一部として使用でき、スパンをターゲットにできるようになりました。これは、unsafeキーワードを使用せずに実行できます。したがって、書く代わりに
Span<byte> bytes;
unsafe
{
byte* tmp = stackalloc byte[length];
bytes = new Span<byte>(tmp, length);
}
簡単に書くことができます:
Span<byte> bytes = stackalloc byte[length];
これは、操作を実行するためにスクラッチスペースが必要であるが、比較的小さなサイズのヒープメモリの割り当てを避けたい場合にも非常に便利です
Span<byte> bytes = length <= 128 ? stackalloc byte[length] : new byte[length];
... // Code that operates on the Span<byte>