다음을 통해 공유


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
    

    참고 항목

    스택 할당 메모리로 작업할 때는 가능한 한, 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이 throw됩니다. 이를 방지하려면 다음 규칙을 따르세요.

  • stackalloc을 사용하여 할당하는 메모리의 양을 제한합니다. 예를 들어, 의도한 버퍼 크기가 특정 한도 미만이면 스택에 메모리를 할당합니다. 그렇지 않으면 다음 코드와 같이 필요한 길이의 배열을 사용합니다.

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

    참고

    스택에서 사용 가능한 메모리 양은 코드를 실행하는 환경에 따라 달라지므로 실제 제한 값을 정의할 때는 신중해야 합니다.

  • 루프 내부에서 stackalloc을 사용하지 마세요. 루프 외부에서 메모리 블록을 할당하고 루프 내부에서 다시 사용합니다.

새로 할당된 메모리의 콘텐츠는 정의되지 않습니다. 이니셜라이저를 사용하거나 사용 전과 stackalloc 같은 Span<T>.Clear 메서드를 사용하여 초기화해야 합니다.

Important

할당된 stackalloc 메모리를 초기화하지 않는 것은 연산자의 중요한 차이점 new 입니다. 연산자를 new 사용하여 할당된 메모리는 0비트 패턴으로 초기화됩니다.

배열 이니셜라이저 구문을 사용하여 새로 할당된 메모리의 콘텐츠를 정의할 수 있습니다. 다음 예제에서는 이 작업을 수행하는 다양한 방법을 보여 줍니다.

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 허용을 참조하세요.

참고 항목