DevSight

C#, Native Safe Buffer 구현

Native Safe Buffer를 구현하기 위해 ref structNativeMemory 클래스를 사용한다. ref struct는 주로 실제 메모리 주소(포인터)를 들고 있는 Span<T>을 안전하게 만들기 위해 존재하고 그 메모리를 안전하고 빠르게 다루는 규칙이라고 할 수 있다.

NativeMemory 클래스는 가비지 컬렉터(GC)의 관리를 받지 않는 네이티브 힙 메모리를 직접 할당하고 관리할 수 있게 해주는 도구인데, 기존의 Marshal.AllocHGlobal이나 stdole 등을 이용하던 방식보다 성능이 뛰어나고 C 언어의 mallocfree와 유사한 인터페이스를 제공한다.

다만 GC가 메모리를 치워주지 않으므로 Free호출이 필수이며, 잘못된 주소에 접근하면 프로그램이 즉시 Access Violation 될 수 있다.

메모리 할당 주체
  • 배열로부터 가져올 때: Span<byte> span = new byte[1024]; : 이것은 결국 Managed 배열이고. GC가 관리하며, 대용량일 경우 GC 부하(LOH 등)가 발생한다.
  • 스택으로부터 가져올 때: Span<byte> span = stackalloc byte[1024]; : GC 부하가 없고 빠르지만, 크기 제한이 엄격하며 보통 1MB가 넘어가면 StackOverflowException 발생
  • 네이티브 메모리로부터 가져올 때: NativeMemory.Alloc(...count...) : 가장 빠르고 크기 제한도 없지만, 수동으로 해제(Free) 하지 않으면 메모리 누수(Memory Leak)가 발생

stackalloc으로 만든 Span은 그 함수가 끝나면 사라지지만 네이티브 메모리로 만든 NativeSafeBuffer는 (비록 ref struct라 제약은 있지만) Dispose를 호출하기 전까지는 메모리가 안정적으로 유지된다.

비교 항목new byte[] (Span)stackalloc (Span)NativeSafeBuffer
관리 주체가비지 컬렉터 (GC)스택 (Stack)OS (Native)
해제 시점GC가 한가할 때함수 종료 시 즉시Dispose 호출 시 즉시
크기 제한힙 메모리만큼매우 작음 (1MB)RAM 용량만큼
안전성매우 안전함빠르지만 위험함수동 해제 필수 (using)
NativeSafeBuffer.cs
Read More ···