[Effective C# Item 17] 표준 Dispose 패턴을 구현하라
[Effective C# Item 17] 표준 Dispose 패턴을 구현하라
이번 포스팅은 메모리가 아닌 다른 유형의 비관리(Unmanaged) 리소스를 포함한는 타입을 작성할 때 리소스 관리를 어떻게 해야 할지를 살펴보는 파트다.
우선 간단하게 비관리 리소스가 무엇인지 살펴보자.
비관리 리소스 : 메모리가 아닌 자원을 말하며, 윈도우 핸들, 파일 핸들, 소켓 핸들 등 시스템 자원을 뜻한다. 반대로 관리 리소스에는 new List<string>() 등, 메모리처럼 쓰는 자원을 말한다.
이런 비관리 리소스들은 가비지 콜렉터가 아닌 개발자가 직접 관리해줘야 한다. 이미 .NET 프레임워크에는 비관리 리소스를 정리하는 표준화된 패턴을 사용하고 있다.
그것이 바로 Dispose 패턴이다.
Dispose 패턴 왜 사용해야 되냐?
우선 Dispose 패턴은 앞서 말했듯 비관리 리소스를 관리하기 위한 패턴이다.
이 패턴을 이용하면 개발자들에게 IDisposable 인터페이스를 통해서 리소스를 삭제할 수 있는 기능을 안정적으로 제공할 수 있다.
또, 비관리 리소스를 명시적으로 정리해야 한다는 사실을 잊어버리거나 인지하지 못한 경우에도 finalizer를 통해 올바르게 리소스가 정리될 수 있도록 해준다.
비관리 리소스를 포함하는 클래스는 반드시 finalizer는 호출하도록 해야 하지만 그런 경우가 아니라면 성능에 부정적인 영향을 미치는 것은 최소화한다.
finalizer가 왜 성능에 안 좋나?
1. finalizer를 구현한 객체는 바로 메모리에서 제거되지 않고 가비지 콜렉터가 finalizer 큐라는 곳에 이 객체들의 참조를 삽입해둔다.
2. 이후에 finalizer 스레드라는 특별한 스레드를 이용하여 finalizer를 순차적으로 호출된다. 이 이후에 이 객체들은 가비지 컬렉터에 의해서 제거될 수 있는 대상으로 간주한다.
3. 이 때문에 다른 객체에 비해서 상대적으로 메모리에 오래 살아남는다.
즉, 메모리에 오래 남는 타입이고 한 세대 높아지고 가비지 콜렉터가 finalizer 객체 검사하는 과정에서 연산을 잡아먹는다.
IDisposable.Dispose() 메서드 수행
1. 모든 비관리 리소스를 정리한다.
2. 모든 관리 리소스를 정리한다.
3. Dispose() 한 후 다시 Dispose()를 호출할 경우 문제가 없도록 객체가 이미 정리되었음을 나타내기 위한 상태 플래그 설정.
4. Dispose() 한 후 비관리 리소스를 사용 시, ObjectDisposed() 예외를 발생 시켜야 한다.
5. finalizer 호출 회피. 이를 위해 GC.SupperessFinalize(this)를 호출한다.
finalizer에서는 비관리 리소스 정리만!!
finalizer를 가진 객체는 최종적으로 정리가 완료되기 이전에 다시 한 번 코드를 수행할 기회를 얻게 된다. 하지만 이 순간에도 쓸데 없는 짓 하지말고 비관리 리소스를 삭제하는 작업만 수행되어야 한다.
이유
1. 가비지 콜렉터는 finalizer 객체에 대해서 이미 finalizer를 호출했으므로 더이상 finalizer를 호출할 필요가 없다고 간주한다. 때문에 되살아난 객체를 진짜 삭제하려고 할 때 finalizer를 호출할 수 없다.
2. 객체가 살아난 것처럼 보이겠지만 finalize 과정 이후엔 가비지로 간주되어 필드를 사용할 수 없다.
정리
새로 작성할 타입이 비관리 리소스를 포함하거나 혹은 IDisposable을 구현한 다른 타입을 포함해야 하는 경우에만 finalizer를 제한적으로 구현하면 된다.
IDisposable 인터페이스만 필요하고 finalizer를 구현할 필요가 없는 경우라 하더라도 표준 Dispose 패턴의 구조는 온전히 유지하는 것이 좋다.
그렇지 않으면 파생 클래스에서 표준 Dispose 패턴을 구현하는 것이 복잡해진다.
Dispose() 메서드를 사용해본 경험이 한, 두번 밖에 없고 그마저도 그냥 시도만 해보고 다시 지웠던 것으로 기억한다.
Dispose라는 개념도 비관리 리소스라는 개념도 너무 익숙치 않다보니 이번 챕터을 읽는데 많은 어려움을 겪었다.
다음 달쯤 C# 기본서를 살 예정인데 이번에 C#을 제대로 다시 공부할 때 비관리 리소스 부분도 눈여겨 봐야겠다.
그리고 다시 이 Item을 다시 보는 방향으로 해야겠다.
참조 - Effective C# <강력한 C# 코드를 구현하는 50가지 전략과 기법, 이펙티브>, 빌 와그너, 김명신, 한빛미디어
<기록, 그리고 생각, 최익필> - https://www.ikpil.com/1190?category=267073