C# .NET: Dispose (소멸자) 패턴
알게된 배경
클래스가 프로그래밍 언어에서 등장할 때 가장 먼저 배우는 것이 생성자이다. 이후 생성자의 반대 개념인 소멸자(혹은 파괴자, 제거자 등 여러 이름으로 부를 수 있는 개념)개념이다.
이는 기존 C++ 같은 언어에서 힙(요즘에는 이 힙을 자유공간(Free Space)라고 부르자고 제안되고 있음)에 할당된 메모리를 관리(할당과 해제)를하기 위해서였다.
그러나 시간이 지나고 나서 GC(Garbage Collection)가 등장하고 나서 부터는 소멸자의 존재 의미가 애매 해졌다. C# DotNet Core 에서부터는 소멸자가 사라지게 되었지만, 기존의 DotNet FrameWork의 경우 아직도 소멸자가 건재하다.
DotNet FrameWork에서는 메모리 관리 방법이 Management와 Unmanagement로 2가지 방법이 있다. Management는 말그대로 CLR이 관리를 해준다(이는 GC의 동작도 포함). 반면, Unmanagement는 CLR이 관여를 하지 않는다. 이렇게 Unmanagement한 영역은 Stream을 사용하는 부분과 소켓 프로그래밍을 위한 버퍼 등이 포함된다. 이러한 영역은 개발자가 직접 해제하는 코드를 작성해줘야 하는데, 이럴때 사용되는 것이 소멸자였다.
그러나 DotNet FrameWork에서는 Dispose라는 인터페이스를 제공을 해주고 있는데, 이 인터페이스는 GC가 해당 Class의 인스턴스를 제거할 때 해당 작업을 먼저 하도록 되어 있다. 문제는 앞에서 언급된 Dispose 인터페이스와 소멸자의 역할이 유사하다 보니 오작동 될 가능성이 있다. 때문에 이러한 패턴이 생겨나게 되었다.
Dispose 메서드는 IDisposeable 인터페이스를 상속 받아서 구현하면, using() 으로 호출하면 해당 스코프(혹은 스택)을 벗어나면, 호출이 된다.
패턴 예제
using System.Net.Sockets;
class UdpListenClass : IDisposeable
{
private UdpClient Listener { get; private set; }
// .. 중략
// Start Destroyer Pattern
private bool _disposed = false;
private void Dispose(bool calledDestroyer)
{
if(false == _disposed)
{
// 소켓을 닫거나 Unmamagement 메모리를 여기서 해제하면 된다
Listener.Close();
_disposed = true;
}
if(false == calledDestroyer)
{
GC.SuppressFinalize(this);
}
}
public void Dispose()
{
Dispose(false);
}
~UdpSocket()
{
Dispose(true);
}
// End Destroyer Pattern
// ... 중략
}
혹시나 오해가 될까 추가로 적자면, 소멸자는 ~[클래스명]으로 선언 정의 된다. Dispose는 소멸자가 아니지만, using문 패턴에서 호출되는 인터패이스다. 그리고 최근에 나오고 있는 DotNet Core에서는 소멸자를 더 이상 사용하지 않는다.
물론 DotNet FrameWork랑 독립적으로 업데이트가 되고 있지만, 새로운 기능을 2017년 8월부터 DotNet Core에 먼저 추가가 되고 이후에 DotNet FrameWork에 추가 할 것이라고 MS에서 발표를 했으니 참조만 하자
참고 자료
도서: 시작하세요. C# 6.0
도서: C# 7과 닷넷 코어 2.0
'C#' 카테고리의 다른 글
C# : using문의 기능과 활용 (0) | 2018.05.15 |
---|---|
C# .NET : SQLLocalDB (1) 개요와 오류사례 (0) | 2018.03.23 |
C# : this와 base (0) | 2018.02.20 |
C# Winform : Detect Resize (크기 변화 감지) (0) | 2018.02.07 |
C# : Queue VS ConcurrentQueue (0) | 2018.02.02 |