stackalloc 式 (C# リファレンス)

stackalloc 式を使用すると、スタックにメモリ ブロックを割り当てることができます。 メソッドの実行中に作成されてスタックに割り当てられたメモリ ブロックは、そのメソッドが戻るときに自動的に破棄されます。 stackalloc を使用して割り当てられたメモリを明示的に開放することはできません。 スタックに割り当てられたメモリ ブロックは、ガベージ コレクションの対象外であり、fixed ステートメントを使用してピン留めする必要はありません。

stackalloc 式の結果を、次のいずれかの型の変数に割り当てることができます。

  • 次の例のように System.Span<T> または System.ReadOnlySpan<T>

    int length = 3;
    Span<int> numbers = stackalloc int[length];
    for (var i = 0; i < length; i++)
    {
        numbers[i] = i;
    }
    

    スタックに割り当てられたメモリ ブロックを Span<T> 変数または ReadOnlySpan<T> 変数に割り当てるときに、unsafe コンテキストを使用する必要はありません。

    これらの型を操作するときに、次の例に示すように、条件式または代入式の中で stackalloc 式を使用できます。

    int length = 1000;
    Span<byte> buffer = length <= 1024 ? stackalloc byte[length] : new byte[length];
    

    次の例のように、Span<T> または ReadOnlySpan<T> の変数が許可されるところでは、他の式の中で stackalloc 式またはコレクション式を使用できます。

    Span<int> numbers = stackalloc[] { 1, 2, 3, 4, 5, 6 };
    var ind = numbers.IndexOfAny(stackalloc[] { 2, 4, 6, 8 });
    Console.WriteLine(ind);  // output: 1
    
    Span<int> numbers2 = [1, 2, 3, 4, 5, 6];
    var ind2 = numbers2.IndexOfAny([2, 4, 6, 8]);
    Console.WriteLine(ind2);  // output: 1
    

    Note

    スタックに割り当てられたメモリを操作するときは、できるだけ Span<T> 型または ReadOnlySpan<T> 型を使用することをお勧めします。

  • ポインター型。次に例を示します。

    unsafe
    {
        int length = 3;
        int* numbers = stackalloc int[length];
        for (var i = 0; i < length; i++)
        {
            numbers[i] = i;
        }
    }
    

    前の例に示したように、ポインター型を操作するときは、unsafe コンテキストを使用する必要があります。

    ポインター型の場合、ローカル変数宣言でのみ stackalloc 式を使用し、変数を初期化できます。

スタックで使用可能なメモリ容量は制限されています。 スタックに割り当てたメモリが多すぎると、StackOverflowException がスローされます。 これを回避するために、次の規則に従ってください。

  • stackalloc を使って割り当てるメモリ容量を制限する。 たとえば、目的のバッファー サイズが特定の制限を下回る場合は、スタックにメモリを割り当てます。それ以外の場合は、次のコードに示すように、必要な長さの配列を使用します。

    const int MaxStackLimit = 1024;
    Span<byte> buffer = inputLength <= MaxStackLimit ? stackalloc byte[MaxStackLimit] : new byte[inputLength];
    

    注意

    スタックで使用可能なメモリ容量はコードが実行される環境によって異なるため、実際の制限値は控えめに定義する必要があります。

  • ループ内での stackalloc の使用を避ける。 ループの外側でメモリ ブロックを割り当て、それをループ内で再利用してください。

新しく割り当てられたメモリの内容は未定義です。 これは、使用する前に初期化する必要があります。 たとえば、すべての項目を T 型の既定値に設定する Span<T>.Clear メソッドを使用できます。

配列初期化子構文を使用して、新しく割り当てられたメモリの内容を定義できます。 これを実行するさまざまな方法を次の例に示します。

Span<int> first = stackalloc int[3] { 1, 2, 3 };
Span<int> second = stackalloc int[] { 1, 2, 3 };
ReadOnlySpan<int> third = stackalloc[] { 1, 2, 3 };

// Using collection expressions:
Span<int> fourth = [1, 2, 3];
ReadOnlySpan<int> fifth = [1, 2, 3];

stackalloc T[E] では、Tアンマネージド型である必要があり、E は負でない int 値に評価される必要があります。 コレクション式の構文を使用してスパンを初期化すると、コンパイラは、ref の安全性に違反しない場合、スパンにスタック割り当てストレージを使用することがあります。

セキュリティ

stackalloc を使用すると、共通言語ランタイム (CLR) のバッファー オーバーラン検出機能が自動的に有効になります。 バッファー オーバーランが検出されると、悪意のあるコードが実行される可能性を最小限に抑えるために、プロセスはできる限り迅速に終了されます。

C# 言語仕様

詳細については、C# 言語仕様に関するページの「スタック割り当て」セクションと、入れ子になった stackalloc の許可に関する機能提案メモをご覧ください。

関連項目