Finalize란 무엇인가?
Finalize() 메서드는 가비지 컬렉터(Garbage Collector)가 수집 대상으로 판단한 객체를 실제로 회수하기 직전에 호출하는 종료자(Finalizer)입니다. 가비지 컬렉터는 더 이상 참조되지 않는 객체의 메모리 해제를 담당하며, 해당 객체에 대한 유효한 참조가 메모리에서 사라진 이후 적절한 시점에 이 메서드를 호출합니다.
다만 .NET 프레임워크는 이 호출 시점을 보장하지 않습니다. 개발자가 GC.Collect() 등으로 가비지 컬렉션을 강제로 유도할 수는 있지만, 이는 프로그램 전체 성능에 부정적인 영향을 미치므로 권장되지 않습니다. 또한 Finalize()는 최상위 클래스인 Object 클래스에 정의되어 있으며, 런타임에 의해 자동으로 호출됩니다.
Finalize 사용 예제
using System;
namespace DemoApplication{
public class Demo{
~Demo(){
Console.WriteLine("Finalize called");
}
}
}C#에서는 위 예제처럼 클래스 이름 앞에 물결표(~)를 붙여 소멸자 형태로 작성하면, 컴파일러가 내부적으로 이를 Finalize() 메서드 오버라이드로 변환합니다.
Dispose란 무엇인가?
반면 윈도우 핸들, 데이터베이스 연결, 네트워크 연결, 파일 스트림과 같은 비관리(unmanaged) 리소스는 가비지 컬렉터가 자동으로 회수할 수 없습니다. 이러한 리소스를 명시적이고 신속하게 해제하려면 IDisposable 인터페이스를 구현하고 그 안의 Dispose() 메서드를 재정의하는 것이 가장 바람직한 방법입니다.
Dispose() 메서드는 런타임이 자동으로 호출해 주지 않으므로, 클라이언트 코드에서 객체 사용이 끝나는 시점에 반드시 명시적으로 호출해야 합니다. 흥미로운 점은 객체를 가리키는 다른 참조가 아직 살아 있더라도 Dispose()를 호출할 수 있다는 것입니다. 일반적으로 C#의 using 문을 활용하면 예외 발생 여부와 관계없이 Dispose 호출을 보장할 수 있습니다.
Dispose 사용 예제
using System;
namespace DemoApplication{
public class Demo : IDisposable{
private bool disposed = false;
public void Dispose(){
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing){
if (!disposed){
if (disposing){
//관리(managed) 리소스 정리
}
//비관리(unmanaged) 리소스 정리
disposed = true;
}
}
}
}위 코드는 Microsoft가 권장하는 표준 Dispose 패턴(Standard Dispose Pattern)을 따른 것입니다. 공개된 Dispose()가 내부의 보호된 Dispose(bool)을 호출하며, 이미 해제 작업이 수행되었는지 여부를 플래그로 관리해 중복 해제를 방지합니다. 또한 GC.SuppressFinalize(this)를 호출하여 가비지 컬렉터가 불필요하게 Finalize를 실행하지 않도록 함으로써 성능을 최적화합니다.
Finalize와 Dispose의 핵심 차이점
호출 주체: Finalize는 가비지 컬렉터가 호출하지만, Dispose는 개발자가 코드에서 직접 호출해야 합니다.
호출 시점: Finalize는 객체가 회수될 때 언젠가 실행되며 시점을 예측할 수 없고, Dispose는 원하는 즉시 리소스를 해제할 수 있습니다.
성능 영향: Finalize가 정의된 객체는 회수 과정에서 추가 단계를 거치므로 성능 부담이 있으며, Dispose에는 이러한 부담이 없습니다.
결론: 두 메서드를 함께 구현해야 하는 이유
Microsoft는 비관리 리소스를 다룰 때 Dispose와 Finalize를 모두 구현할 것을 권장합니다. 개발자가 실수로 Dispose() 호출을 누락하더라도, 객체가 최종적으로 가비지 컬렉션되는 시점에 Finalize 구현이 실행되어 리소스가 반드시 해제되기 때문입니다. 즉, Dispose는 빠르고 확실한 리소스 해제의 기본 수단이며, Finalize는 이를 놓친 경우를 대비한 최후의 안전망 역할을 한다고 이해하면 됩니다.