소멸자는 개체가 소멸할 때 수행해야 할 작업에 대한 코드 블록입니다. 소멸자는 클래스에서만 정의할 수가 있고 구조체에는 정의할 수 없습니다. C++에서는 동적으로 생성된 개체를 개발자가 소멸시켜야 합니다. 하지만 C#에서는 .NET 플랫폼의 가비지 수집기가 주기적으로 개체 수명을 조사를 통해 개체를 참조하는 변수가 없는 개체를 확인하고 정책에 의해 자동으로 소멸합니다.
이에 소멸자의 접근 한정자는 개발자가 명시할 수 없습니다. 그리고 다른 메서드들과 달리 중복 정의할 수도 없습니다. 소멸자의 이름은 형식 이름 앞에 ~가 붙습니다. 그리고 가비지 수집기가 소멸되는 시점에 자동으로 호출합니다.
class Man { ~Man() { Console.WriteLine("소멸자"); } }
컴파일러는 소멸자를 정의하면 컴파일러에서는 Finalize 메서드를 호출하는 코드로 변환됩니다. ildasm 유틸리티를 이용하여 덤프해 보면 이를 확인하실 수 있습니다.
▶ildasm으로 덤프한 IL코드
.method family hidebysig virtual instance void Finalize() cil managed { // 코드 크기 25 (0x19) .maxstack 1 .try { IL_0000: nop IL_0001: ldstr bytearray (4C C7 ) // L. IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: nop IL_000d: leave.s IL_0017 } // end .try finally { IL_000f: ldarg.0 IL_0010: call instance void [mscorlib]System.Object::Finalize() IL_0015: nop IL_0016: endfinally } // end handler IL_0017: nop IL_0018: ret } // end of method Man::Finalize
이처럼 개발자가 소멸자를 정의하면 컴파일러에 의해 묵시적으로 Finalize 메서드로 변환이 되고 가비지 수집기로 개체가 소멸하는 작업을 수행하게 됩니다. 만약, 소멸하는 시점에 특별히 할 작업이 없는데도 비어있는 소멸자를 정의하면 비어있는 Finalize 메서드를 수행하게 됩니다. 따라서 비어있는 소멸자는 정의하지 마시기 바랍니다.
또한, 외부 자원을 사용하는 경우에 명시적으로 자원 해제를 원한다면 Dispose 메서드를 정의하여 성능을 높일 수 있습니다.
▶ IDisposable 인터페이스 기반의 클래스 정의
class Man:IDisposable { bool isdispose; ~Man() { Dispose(); } public void Dispose() { if ( ! isdispose ) { //자원 해제 구문 } isdispose = true; } }