개발공부/C#

[Effective C#] 아이템 17 : 표준 Dispose 패턴을 구현하라

개발자 찐빵이 2021. 11. 23. 22:35
728x90

Dispose 란?

비관리 리소스를 해제하기 위해 사용하는 함수

비관리 리소스란?

메모리가 아닌 시스템 자원을 말한다. (ex. 윈도우 핸들, 파일 핸들, 소켓 핸들 등)

관리 리소스란?

메모리처럼 쓰이는 자원 (ex. new List<int>() 등)

표준 Dispose 패턴이란?

  1. IDisposable 인터페이스로 Dispose를 구현한다.
  2. Dispose 내부에서는 비관리 리소스를 해제한다.
  3. 사용자가 Dispose를 사용하지 않을 경우를 대비해서 finalizer를 구현한다.
  4. finalizer에서 비관리 리소스를 해제한다.

위 조건을 구현한 Dispose를 표준 Dispose 패턴이라고 한다.

IDisposable 란?

비관리 리소스를 정리하는 표준화된 방법.
최종 사용자에게 적시에 리소스를 해제할 수 있는 메커니즘을 안전하게 제공한다.
finalize 과정으로 발생하는 불필요한 비용을 피할 수 있다.

finalizer가 성능에 안좋은 영향을 주는 이유

  1. 가비지 수집 작업이 진행되어도 가비지 객체가 메모리에 남아있다.
  2. 가비지 수집 작업이 수차례 반복되어 해당 세대에 대한 가비지 수집이 수행되면 비로소 객체들이 제거될 수 있다.

그래도 finalizer를 구현해야 하는 이유

finalizer는 비관리 리소스가 누수되지 않고 올바르게 정리됨을 보장하기 때문에 꼭 필요하다.

IDisposable.Dispose() 메서드에서 반드시 수행해야 하는 작업

  1. 모든 비관리 리소스 정리
  2. 모든 관리 리소스 정리
  3. 객체가 정리되었음을 나타내기 위한 상태 플래그 설정.
    앞서 정리된 객체에 대해 추가로 정리 작업이 요청될 경우, 이 플래그를 확인해서 ObjectDisposed 예외를 발생시킨다.
  4. finalizer 호출 회피.
    이를 위해 GC.SuppressFinalize(this)를 호출한다.

주의할 점

  • Dispose와 finalizer는 방어적으로 작성되어야 한다.
    Dispose 메서드는 한번 이상 호출될 수 있기 때문에 여러 번 호출해도 문제없도록 구현되어야 한다.
    만약 이미 정리된 객체에 대해 호출한 경우 ObjectDisposedException 예외를 발생시키는 것이 Dispose 패턴의 규칙이다.
  • Dispose 메서드 내에서는 리소스 정리 작업만 수행한다.
    Dispose나 finalizer에서 다른 작업을 수행하게 되면 객체의 생명 주기와 관련된 심각한 문제를 일으킬 수 있다.
    만약 finalizer에서 객체에 접근해서 다른 작업을 수행하면, 객체는 'reachable'상태가 되어 죽지 않고 다시 살아날 수 있다.
반응형