포스트를 만든 목적

  • 이렇게 하지 않으면, 책을 건성으로 본다.

내용

Dispose 는 무엇인가?

관리되지 않는(unmanaged) 자원을 해제하기 위해서 사용 하는 함수이다.

그러면 unmanaged 자원은 무엇인가?

쉽게 생각해서 "메모리가 아닌 자원" 즉, 윈도우 핸들, 파일 핸들, 소켓 핸들 등 시스템 자원을 뜻한다. 반대로 managed 는.. new List<int>() 등, 메모리 처럼 쓰는 자원들이다.

그러면 표준 Dispose 패턴은 무엇인가?

  1. Dispose를 IDisposable Interface로 구현한다.
  2. Dispose 내부에선 unmanaged 자원을 해제한다.
  3. 사용자가 Dispose를 사용하지 않았을 경우를 대비하여, finalizer를 구현한다.
  4. finalizer 에서 unmanaged 자원을 해제한다.
이 1 ~ 4 을 구현한 Dispose 를 표준 Dispose 패턴이라고 한다.

finalizer 를 구현하면, 성능상에 나쁜 영향을 주는데, 왜 finalizer를 구현해야 하나?

무제한 unmanaged 자원이 늘어나는게 더 나쁜 영향을 준다. 그래도 finalizer를 구현하지 않겠는가?

왜 finalizer를 구현하면 성능에 나쁘나?

  1. finalizer를 구현하면, GC가 자신이 관리하는 finalizer 큐에 저장한다.
  2. GC에서 사용하는 특정 쓰레드가 finalizer 큐를 읽고, 해제해도 되는지 검사한다.
  3. 검사 후 해제되도 된다면, 그때서야 해제한다.

3번이 될때까지 아직도 해제하지 않고 있는 것과, 검사하는 것에 에너지를 사용하기 때문에 성능에 나쁘다.(얼마나 나쁠지는 모르겠다.)

finalizer에선 어떤 일을 해야 하는가?

사용자가 Dispose()를 사용하지 않았을 경우, unmanaged 자원을 해야 해야 한다.

그러면, 어떻게 Dispose를 구현해야 하는가?

반드시 다음과 같은 기능을 수행해야만 한다.

  1. unmanaged 자원 해제
  2. managed 자원의 해제
  3. Dispose() 한 후 다시 Dispose() 호출 후 이상이 없어야 한다.
  4. Dispose() 한 후 unmanaged 자원 사용 시, ObjectDisposed 예외를 발생 시켜야 한다.
  5. finalization 동작을 막아야 한다.

다 좋은데, 상속 기반에서는 어떻게 하나? IDisposable Interface는 비가상 함수지 않는가?

그렇다. 그래서 가상함수로 Dispose() 기능을 수행하는 함수를 만들어야 한다. 기왕 제 3의 함수 만드니까, finalizer 에서 사용 되는 부분도 줄이면 좋겠다.

.. 그런데 managed 자원은 GC(가비지 켈렉터)가 해제해주는데 굳이 해제해 줄 필요가 있는가?

맞는 말이다. 하지만 어차피 사용되지 않을꺼니까, 가비지 켈렉터가 잘 일할 수 있도록, 해제해 주는게 좋다.

어떻게 managed 자원을 해제 하는가?

.. null 로 만들면 된다. 예를 들어 _list.Clear(); _list = null; 이렇게 하면 된다.

자, 이제 코드로 보여 줄 수 있는가?


주의 해야 할 점이 있는가?

  • finalizer 와 Dispose 에서, 객체 생명주기를 바꾸는 행동을 하지 말아야 한다. 만약 객체 생명주기를 건들게 되면, 객체는 더 이상 사용하지 않는데도, managed 자원까지 사라지지 않는 일이 발생 한다. .... 어렵다면, 해제하는 작업만 해야 한다고 알아도 된다.

결론

  • 남이 만든거 갔다가 쓰자. :P
  • 남이 만든게 없을 경우, unmanaged 자원이 있을 경우, 표준 Dispose 패턴으로 구현하자.

여담

  • 역시 남이 만든거 갔다가 쓰는게 최고다. :P ... 예제를 만들어 보니, .. 손갈 때가 많더라..
  • 이 포스트 남기고, 내가 찾아와서 봐야할 판이다.


  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 라이프코리아트위터 공유하기
  • shared
  • 카카오스토리 공유하기