P/Invoke
C# 언어에서 Windows API나 기존 C/C++ 언어 라이브러리를 직접 호출해야할 때 P/Invoke를 사용한다.
-
[DLLImport]와 마샬링(Marshalling): C# 관리 환경의 데이터 타입을 C/C++ 언어의 비관리 환경 데이터 타입으로 변환하여 전달하는 과정이다. -
상호 운용성 위험: 비관리 코드는 가비지 컬렉터의 통제를 받지 않으므로 잘못된 메모리 주소 참조 시 프로그램이 예기치 못하게 종료될 수 있다.
IntPtr 한계와 세이프 핸들의 등장
과거에는 비관리 리소스를 IntPtr 숫자로 관리했지만, 이는 치명적인 문제를 야기했고 세이프 핸들(Safe Handle)가 등장하는 계기였다.
-
핸들 재활용 공격(Handle Recycling Attack): 비관리 리소스가 해제된 직후 다른 스레드가 그 번호를 가로채어 엉뚱한 자원에 명령을 내리는 보안 취약점이다.
-
세이프 핸들의 해결책: SafeHandle은 CriticalFinalizerObject를 상속받아, 앱 도메인이 강제 종료되는 상황에서도 반드시 해제 로직이 실행되도록 보장한다.
-
참조 횟수 관리: .NET 런타임이 내부적으로 핸들의 참조 횟수를 관리하여 사용 중인 핸들이 실수로 닫히는 것을 방지한다.
비관리 리소스 해제 패턴
단순히 Dispose() 메소드를 구현하는 것보다 견고한 해제 패턴을 다룬다.
-
TrySpecifySafeHandle 패턴: 핸들을 생성하는 순간부터 SafeHandle 객체에 소유권을 안전하게 이전하는 기법이다.
-
소멸자(Finalizer)와의 관계: 현대적인 C# 언어에서는 직접 소멸자를 작성하지 말고 SafeHandle 객체를 필드로 두어야 한다.
-
비관리 메모리 고정(GCHandle): 비관리 코드에 전달한 데이터가 가비지 컬렉터에 의해 이동하지 않도록 메모리에 핀 고정(Pinning)하는 방법이 있다.