C#고급 주제

Span, ReadOnlySpan, Memory

문자열과 버퍼를 불필요하게 복사하지 않기 위해 `Span<T>`, `ReadOnlySpan<T>`, `Memory<T>`를 어떤 기준으로 구분해 쓰는지 정리합니다.

마지막 수정 2026년 3월 22일

기본 패턴

csharp
ReadOnlySpan<char> name = "RefDock".AsSpan();
ReadOnlySpan<char> first = name[..3];

설명

  • Span<T>ReadOnlySpan<T>는 연속 메모리를 복사 없이 바라보는 stack-only view입니다. 배열 일부, 문자열 일부, 버퍼 조각을 잘라 다룰 때 특히 강력합니다.
  • 핵심 장점은 allocation을 줄인다는 점입니다. 예를 들어 문자열 일부를 파싱할 때 새 Substring을 계속 만드는 대신 span으로 조각만 바라보면 메모리 부담이 줄어듭니다.
  • 하지만 Span<T>ref struct이기 때문에 heap에 저장하거나 await 경계를 넘길 수 없습니다. 이 제한이 바로 Memory<T>가 필요한 이유입니다.
  • Memory<T>ReadOnlyMemory<T>는 비슷한 역할을 하지만 heap에 둘 수 있어 비동기 흐름과 더 잘 맞습니다. 그래서 "동기 처리면 span, 비동기 경계까지 들고 가야 하면 memory"라는 큰 기준이 생깁니다.
  • 이 주제의 핵심은 성능보다 수명과 경계입니다. 어떤 버퍼를 누가 소유하는지, 언제까지 유효한지, 동기/비동기 중 어디까지 전달되는지를 함께 봐야 안전하게 쓸 수 있습니다.

빠른 정리

타입특징
Span<T>가변, stack-only, 동기 처리에 적합
ReadOnlySpan<T>읽기 전용 stack-only view
Memory<T>heap 보관 가능, 비동기 경계에 적합
핵심 장점복사와 allocation 감소
핵심 제약span은 await/heap 저장 불가

주의할 점

Span<T>는 빠르지만 수명 제약이 강합니다. 성능 최적화 욕심으로 들고 가기보다, "이 버퍼가 동기 호출 안에서만 살아도 되는가" 를 먼저 판단하는 편이 좋습니다.

참고 링크

3 sources