종료자(C# 프로그래밍 가이드)Finalizers (C# Programming Guide)

종료자(소멸자라고도 함)는 가비지 수집기에서 클래스 인스턴스를 수집할 때 필요한 최종 정리를 수행하는 데 사용됩니다.Finalizers (which are also called destructors) are used to perform any necessary final clean-up when a class instance is being collected by the garbage collector.

설명Remarks

  • 종료자는 구조체에서 정의할 수 없으며,Finalizers cannot be defined in structs. 클래스에서만 사용됩니다.They are only used with classes.

  • 클래스에는 종료자가 하나만 있을 수 있습니다.A class can only have one finalizer.

  • 종료자는 상속하거나 오버로드할 수 없습니다.Finalizers cannot be inherited or overloaded.

  • 종료자를 호출할 수 없습니다.Finalizers cannot be called. 자동으로 호출됩니다.They are invoked automatically.

  • 종료자는 한정자를 사용하거나 매개 변수를 갖지 않습니다.A finalizer does not take modifiers or have parameters.

예를 들어 다음은 Car 클래스에 대한 종료자의 선언입니다.For example, the following is a declaration of a finalizer for the Car class.

class Car
{
    ~Car()  // finalizer
    {
        // cleanup statements...
    }
}

다음 예제와 같이 종료자를 식 본문 정의로 구현할 수도 있습니다.A finalizer can also be implemented as an expression body definition, as the following example shows.

using System;

public class Destroyer
{
   public override string ToString() => GetType().Name;
   
   ~Destroyer() => Console.WriteLine($"The {ToString()} destructor is executing.");
}

종료자는 개체의 기본 클래스에서 Finalize를 암시적으로 호출합니다.The finalizer implicitly calls Finalize on the base class of the object. 따라서 종료자 호출은 다음 코드로 암시적으로 변환됩니다.Therefore, a call to a finalizer is implicitly translated to the following code:

protected override void Finalize()  
{  
    try  
    {  
        // Cleanup statements...  
    }  
    finally  
    {  
        base.Finalize();  
    }  
}  

즉, Finalize 메서드가 상속 체인의 모든 인스턴스에 대해 최다 파생에서 최소 파생까지 재귀적으로 호출됩니다.This means that the Finalize method is called recursively for all instances in the inheritance chain, from the most-derived to the least-derived.

참고

빈 종료자는 사용할 수 없습니다.Empty finalizers should not be used. 클래스에 종료자가 포함되어 있으면 Finalize 큐에서 항목이 생성됩니다.When a class contains a finalizer, an entry is created in the Finalize queue. 종료자를 호출하면 가비지 수집기가 호출되어 큐를 처리합니다.When the finalizer is called, the garbage collector is invoked to process the queue. 종료자가 비어 있으면 성능이 불필요하게 저하됩니다.An empty finalizer just causes a needless loss of performance.

종료자가 호출되는 시기는 가비지 수집기에 의해 결정되기 때문에 프로그래머가 제어할 수 없습니다.The programmer has no control over when the finalizer is called because this is determined by the garbage collector. 가비지 수집기는 애플리케이션에서 더 이상 사용되지 않는 개체를 확인합니다.The garbage collector checks for objects that are no longer being used by the application. 개체를 종료할 수 있는 것으로 판단되면 종료자(있는 경우)를 호출하고 개체를 저장하는 데 사용된 메모리를 회수합니다.If it considers an object eligible for finalization, it calls the finalizer (if any) and reclaims the memory used to store the object.

.NET Framework 애플리케이션에서(.NET Core 애플리케이션에서가 아닌) 프로그램이 종료될 때 종료자도 호출됩니다.In .NET Framework applications (but not in .NET Core applications), finalizers are also called when the program exits.

Collect를 호출하여 강제로 가비지 수집할 수 있지만 대부분의 경우 성능 문제가 발생할 수 있으므로 방지해야 합니다.It is possible to force garbage collection by calling Collect, but most of the time, this should be avoided because it may create performance issues.

종료자를 사용하여 리소스 해제Using finalizers to release resources

일반적으로 C#에서는 가비지 수집을 사용하는 런타임을 대상으로 하지 않는 언어로 개발할 때 필요한 만큼 많은 메모리 관리가 필요하지 않습니다.In general, C# does not require as much memory management as is needed when you develop with a language that does not target a runtime with garbage collection. 이는 .NET Framework 가비지 수집기에서 개체에 대한 메모리 할당 및 해제를 암시적으로 관리하기 때문입니다.This is because the .NET Framework garbage collector implicitly manages the allocation and release of memory for your objects. 그러나 애플리케이션에서 창, 파일 및 네트워크 연결 등의 관리되지 않는 리소스를 캡슐화하는 경우 종료자를 사용하여 해당 리소스를 해제해야 합니다.However, when your application encapsulates unmanaged resources such as windows, files, and network connections, you should use finalizers to free those resources. 개체를 종료할 수 있으면 가비지 수집기에서 개체의 Finalize 메서드를 실행합니다.When the object is eligible for finalization, the garbage collector runs the Finalize method of the object.

리소스의 명시적 해제Explicit release of resources

애플리케이션에서 비용이 많이 드는 외부 리소스를 사용하는 경우 가비지 수집기에서 개체를 해제하기 전에 리소스를 명시적으로 해제하는 방법을 제공하는 것이 좋습니다.If your application is using an expensive external resource, we also recommend that you provide a way to explicitly release the resource before the garbage collector frees the object. 이렇게 하려면 IDisposable 인터페이스에서 개체에 필요한 정리를 수행하는 Dispose 메서드를 구현합니다.You do this by implementing a Dispose method from the IDisposable interface that performs the necessary cleanup for the object. 이렇게 하면 애플리케이션의 성능을 상당히 향상시킬 수 있습니다.This can considerably improve the performance of the application. 이렇게 리소스를 명시적으로 제어하는 경우에도 종료자는 Dispose 메서드 호출에 실패할 경우 리소스를 정리하는 안전한 방법이 됩니다.Even with this explicit control over resources, the finalizer becomes a safeguard to clean up resources if the call to the Dispose method failed.

리소스 정리에 대한 자세한 내용은 다음 항목을 참조하세요.For more details about cleaning up resources, see the following topics:

Example

다음 예제에서는 상속 체인을 구성하는 세 가지 클래스를 만듭니다.The following example creates three classes that make a chain of inheritance. First 클래스는 기본 클래스이고, SecondFirst에서 파생되며, ThirdSecond에서 파생됩니다.The class First is the base class, Second is derived from First, and Third is derived from Second. 세 클래스 모두 종료자가 있습니다.All three have finalizers. Main에서 최다 파생 클래스의 인스턴스가 만들어집니다.In Main, an instance of the most-derived class is created. 프로그램이 실행되면 세 클래스에 대한 종료자가 최다 파생부터 최소 파생까지 순서대로 자동으로 호출됩니다.When the program runs, notice that the finalizers for the three classes are called automatically, and in order, from the most-derived to the least-derived.

class First
{
    ~First()
    {
        System.Diagnostics.Trace.WriteLine("First's destructor is called.");
    }
}

class Second : First
{
    ~Second()
    {
        System.Diagnostics.Trace.WriteLine("Second's destructor is called.");
    }
}

class Third : Second
{
    ~Third()
    {
        System.Diagnostics.Trace.WriteLine("Third's destructor is called.");
    }
}

class TestDestructors
{
    static void Main()
    {
        Third t = new Third();
    }

}
/* Output (to VS Output Window):
    Third's destructor is called.
    Second's destructor is called.
    First's destructor is called.
*/

C# 언어 사양C# language specification

자세한 내용은 C# 언어 사양소멸자 섹션을 참조하세요.For more information, see the Destructors section of the C# language specification.

참고 항목See also