방프리
20.07.11 Chapter2. .Net 리소스 관리 (Item 17) 본문
Item 17: 표준 Dispose 패턴을 구현하라
C++에서 코딩할 때 가장 중요한 것은 메모리 관리이다. 솔직히 DirectX나 학교 과제로 MFC 공부할 때, 특히 서버 개발
일을 할 때 메모리 관리하는 것은 굉장히 신경쓰이고 짜증나는 일이었다. C#에서는 가비지 컬렉터가 알아서
처리해주니까 이에 대한 부담감이 확실히 덜하긴 하지만 내부적으로 봤을 때 가비지 컬렉터도 코드로 돌아가고 있는
존재이기 때문에 마냥 안심만은 할 수가 없다. 또한 메모리라는 것이 가비지컬렉터가 알아서 해주면 편하지만 이 시점을
개발자들이 제대로 알 수 없기 때문에 버그를 만들 수도 있다. 예로 언리얼 엔진 서밋에 참가했을 때 맨 처음 C#으로
개발을 진행했던 프로젝트가 메모리가 해제되는 시점을 제대로 알 수 없어서 C++로 다시 바꾸었다는 이야기를 들은
적이 있다. 그렇다고 C++처럼 소멸자를 사용하려고하면 제대로 동작도 안되고 애초에 MSDN에서도 추천하지 않는
방식이다. 그런 문제 때문에 Dispose라는 함수를 통해 표준화된 메모리 해제에 대한 장치를 마련해놨는데 finalizer와
연계되어 동작한다.
이 부분을 위해서 최상위 베이스 클래스에 다음을 구현해야 한다.
* 리소스를 정리하기 위해서 IDisposeable 인터페이스를 구현
* 멤버 필드로 비관리 리소스를 포함하는 경우에 한해 방어적으로 동작할 수 있도록 finalizer를 추가
* Dispose와 finalizer(존재하는 경우)는 실제 리소스 정리 작업을 수행하는 다른 가상 메서드에 작업을 위임하도록 작성.
파생 클래스가 고유의 리소스 정리 작업이 필요한 경우 이 가상 메서드를 재정의 할 수 있도록 한다.
파생클래스에서는 다음을 구현해야 한다.
* 파생 클래스가 고유의 리소스 정리 작업을 수행해야 한다면 베이스 클래스에서 정의한 가상 메서드를 재정의
* 멤버 필드로 비관리 리소스를 포함하는 경우에만 finalizer를 추가
* 베이스 클래스에서 정의하고 있는 가상 함수를 반드시 재호출
C#에서도 IDisposable 인터페이스 덕에 런타임에도 개발자가 적시에 리소스를 정리할 수 있다.
이 인터페이스에서는 단 하나만의 메서드를 가지고 있다.
이 Dispose() 메서드는 다음 네 가지 작업을 무조건 수행한다.
* 모든 비관리 리소스를 정리
* 모든 관리 리소스 정리
* 객체가 이미 정리되었음을 나태내기 위한 상태 플래그 설정. 앞어 이미 정리된 객체에 대하여 추가로 정리 작업이
요청될 경우 이 플래스를 확인하여 ObjectDisposed 예외를 발생
* finalizer 호출 회피. 이를 위해 GC.SupperessFinalize(this) 호출
하지만 이 Dispose도 취약한 부분이 있는데 바로 파생 클래스의 메모리 해제 후 베이스 클래스의 메모리 해제 문제이다.
이의 경우엔 protected로 선언된 virtual void Dispose(bool isDisposing); 이라는 함수를 통해 해결이 가능하다.
이 가상 함수를 통해 fianlizer와 Dispose 양쪽에서 사용이 가능하다. 또한 코드 마지막 부분에서는 베이스 클래스의
Dispose()를 반드시 구현해주어야 한다.
Dispose와 finalizer는 방어적으로 코딩되어야 한다. 그 부분 때문에 위의 코드에서도 return 하는 부분이 추가되었다.
베이스 클래스의 ObjectDisposedExceptioin 예외는 이미 정리된 리소스를 다시 정리하려고 시도할 때의 예외처리
를 위한 구문이다. Dispose는 분명 메모리를 해제하는 부분이다. 어떠한 이유든지 이 부분에서 절대 객체에 메모리를
할당하는 우범을 범하지 않도록 해야한다.
Dispose를 구현한다면 표준을 따르자. 그리고 애초에 소멸자의 구현은 C#에서는 그다지 추천하지 않는다.
'C# > Effective C#' 카테고리의 다른 글
20.10.22 Chapter3. 제네릭 활용 (Item 19) (0) | 2020.10.22 |
---|---|
20.07.17 Chapter3. 제네릭 활용 (Item 18) (0) | 2020.07.17 |
20.05.12 Chapter2. .Net 리소스 관리 (Item 16) (0) | 2020.05.12 |
20.05.11 Chapter2. .Net 리소스 관리 (Item 15) (0) | 2020.05.11 |
20.05.10 Chapter2. .Net 리소스 관리 (Item 14) (0) | 2020.05.10 |