소멸자(Destructor)

  • 11 minutes to read

소멸자(destructor)는 생성자와 반대 개념으로 클래스로부터 인스턴스화된 개체가 메모리 상에서 없어질 때 실행되는 메서드입니다. 자동차 클래스를 예로 든다면 자동차 주차 대행, 시동 끄기, 폐차 등으로 볼 수 있습니다.

> // 소멸자: 클래스가 사용된 후 가장 마지막에 호출되는 메서드로 클래스 사용의 마무리를 담당

종료자(Finalizer)

종료자(Finalizer)로도 불리는 소멸자(Destructor)는 닷넷의 가비지 수집기(Garbage Collector, GC)에서 클래스의 인스턴스를 사용 후 최종 정리를 수행할 때 실행되는 클래스에서 가장 늦게 호출되는 메서드입니다.

C#에서는 닷넷 가비지 수집기(GC)가 개체가 소멸될 때 메모리를 해제하는 등의 역할을 대신해 주기 때문에 이 책에서 소멸자에 직접 접근할 일은 없을 것입니다. 다음 내용은 가볍게 읽고 넘아가면 됩니다.

  • 자동차의 시동을 끄는 것으로 비유가 가능하며, 운전수가 주차하고 시동을 끄는 게 아니라 주차 요원(GC)이 대신 주차하고 시동을 꺼주는 것과 같은 의미입니다.
  • 소멸자는 클래스 이름과 동일한 메서드로 앞에 물결 기호인 ~(틸드) 기호를 붙여 만듭니다.
  • 소멸자도 특별한 형태의 메서드입니다. 소멸자 또한 소멸자 메서드라고도 부릅니다. 생성자와 달리 매개 변수를 받을 수 없습니다.
  • 소멸자는 오버로드를 지원하지 않고 직접 호출할 수 없습니다.

가비지 수집기(Garbage Collector)

C#에서의 메모리 관리는 닷넷에 내장되어 있는 GC라 불리는 가비지 수집기 (garbage collector)가 관리합니다. 개발자가 따로 코드로 관리하는 게 아닌 GC가 메모리를 관리하는 구조입니다.

가비지 컬렉션은 큰 호텔의 주차 요원과 비슷한 역할을 합니다. 우리가 자동차를 타고 호텔 앞에서 내리면, 자동차를 주차하고 시동을 끄는 등의 행위를 운전자인 내가 하는 게 아닌 주차 요원이 대신해주는 시스템입니다. 이러한 경우 현실 세계에서는 비용이 발생하는데, C#의 경우에는 GC가 알아서 해준다고 보면 됩니다. 특정 클래스의 인스턴스를 생성한 후 해당 인스턴스를 제거하는 코드를 따로 사용하지 않아도 되게 하는 것이 GC 엔진의 역할입니다.

가비지 컬렉터(GC; Garbage Collector)

C#은 개체를 생성한 후에 생성된 개체를 소멸시키는 작업을 따로 진행하지 않습니다. 그러한 이유는 가비지 컬렉터로 불리는 프로그램에 의해서 자동으로 개체를 메모리에서 소멸시켜주는 역할을 합니다.

소멸자 만들기

예를 들어, Car 클래스에 소멸자를 만들려면 다음과 같이 표현할 수 있습니다. 물결 기호인 틸드(~) 문자와 클래스 이름을 사용합니다.

class Car
{
    ~Car()
    {
        // 개체가 소멸할 때 필요한 기능 수행 
    }
}

소멸자는 정적 호출 및 인스턴스 호출에 상관없이 동일한 모양입니다.

생성자, 메서드, 소멸자 실행 시점 살펴보기

생성자, 메서드, 소멸자에 대한 간단한 모양과 실행 시점을 비교하는 예제를 만들어보겠습니다.

코드: ConstructorToDestructor.cs

using static System.Console;

public class DestructorTest
{
    // 생성자
    public DestructorTest()
    {
        WriteLine("[1] 생성");
    }
    // 메서드
    public void Run()
    {
        WriteLine("[2] 실행");
    }
    // 소멸자: GC
    ~DestructorTest()
    {
        WriteLine("[3] 소멸");
    }
}

class ConstructorToDestructor
{
    static void Main()
    {
        DestructorTest test = new DestructorTest(); // 생성
        test.Run(); // 실행
        // GC.Collect(); // 소멸
    }
}
[1] 생성
[2] 실행
[3] 소멸

DestructorTest 클래스의 인스턴스 생성시 생성자가 제일 먼저 호출되고 Run() 메서드는 명시적으로 호출할 때 실행되고 개체를 다 사용하고 Main() 메서드가 끝나는 시점에 소멸자가 실행되는 형태로 하나의 개체가 만들어지고 소멸되는 내용을 살펴볼 수 있습니다.

[실습] 소멸자를 통한 클래스의 역할 마무리

소개

소멸자는 클래스로부터 개체가 생성된 후 해당 개체가 더 이상 사용하지 않을 때, 즉 해제되기 직전에 실행되는 메서드의 일종입니다. 개체를 생성 후 소멸자의 실행되는 단계를 코드로서 알아보겠습니다.

따라하기

(1) 새로운 C# 콘솔 프로젝트를 다음과 같이 생성합니다.

프로젝트 형식 템플릿 이름 위치
Visual C# 콘솔 응용 프로그램 DestructorDemo C:\C#

(2) 솔루션 탐색기에서 Program.cs 파일을 DestructorDemo.cs 파일로 이름을 변경한 후 이미 만들어져 있는 모든 코드를 삭제한 후 다음과 같이 프로그램을 작성합니다.

코드: DestructorDemo.cs

using System;

namespace DestructorDemo
{
    public class Car
    {
        private string _name; // 필드
        public string GetName() // 메서드
        {
            return _name;
        }
        public Car() // 생성자(매개 변수가 없는)
        {
            _name = "승용차";
        }
        public Car(string name) // 생성자(매개 변수가 있는)
        {
            this._name = name;
        }
        //[!] 소멸자 : GC가 호출
        ~Car() // 소멸자
        {
            Console.WriteLine("{0} 폐차...", _name);
        }
    }

    class DestructorDemo
    {
        static void Main(string[] args)
        {
            Car car1 = new Car();
            Console.WriteLine(car1.GetName());
            Car car2 = new Car("캠핑카");
            Console.WriteLine(car2.GetName());
        }
    }
}

(3) 소스 코드를 다 입력한 후 Ctrl+F5를 눌러 프로그램을 실행하면 명령 프롬프트 창에 다음과 같이 출력됩니다.

승용차
캠핑카
캠핑카 폐차...
승용차 폐차...

마무리

소멸자는 이번 실습 예제를 다뤄보는 것으로 그 값어치를 다한 것 같습니다. 앞으로 나타나는 모든 코드에는 소멸자를 일부러라도 사용하지 않을 것입니다. 그 이유는 간단합니다. 사용할 필요성이 없기 때문입니다. 어쨌든, 소멸자는 개체가 해제될 때 실행되는 메서드이지만 가비지 컬렉터가 이 모든 작업을 해주기에 개발자가 따로 관여할 코드 부분은 아닌 듯 합니다.

생성자, 메서드, 소멸자 함께 사용하기

이번에는 생성자, 메서드, 소멸자를 모두 사용하는 내용을 만들어보겠습니다.

코드: ConstructorMethodDestructor.cs

using System;

namespace ConstructorMethodDestructor
{
    public class Car
    {
        // [1] 필드
        private string color;
        // [2][1] 생성자: 기본 생성자
        public Car()
        {
            color = "검정";
            Console.WriteLine("{0}색 자동차를 조립합니다.", color);
        }
        // [2][2] 생성자: 매개 변수가 있는 생성자
        public Car(string color)
        {
            this.color = color; // this.필드 = 매개변수;
            Console.WriteLine("{0}색 자동차를 조립합니다.", color);
        }
        // [3] 메서드
        public void Go() => Console.WriteLine("{0}색 자동차가 달립니다.", color);
        // [4] 소멸자: GC 엔진 알아서 소멸시킴
        ~Car() => Console.WriteLine("{0}색 자동차를 폐차합니다.", this.color);
    }

    class ConstructorMethodDestructor
    {
        static void Main()
        {
            // Car 클래스의 인스턴스 생성
            Car car = new Car(); // 생성
            car.Go(); // 호출

            // 폐차: 시점을 알 수 없다. GC 엔진이 알아서 실행

            // 매개변수가 있는 생성자를 호출
            Car whiteCar = new Car("하얀");
            whiteCar.Go();

            Car blueCar = new Car("파랑");
            blueCar.Go();
        }
    }
}
검정색 자동차를 조립합니다.
검정색 자동차가 달립니다.
하얀색 자동차를 조립합니다.
하얀색 자동차가 달립니다.
파랑색 자동차를 조립합니다.
파랑색 자동차가 달립니다.
파랑색 자동차를 폐차합니다.
검정색 자동차를 폐차합니다.
하얀색 자동차를 폐차합니다.

위 실행결과는 다를 수 있습니다. 필드는 클래스의 부품 역할을 하며, 생성자는 기본 생성자와 매개 변수가 있는 생성자를 만들 수 있는 것처럼 생성자 오버로드도 가능합니다. 개체는 생성자를 통해서 생성이되고 메서드 등이 호출되는 형태로 사용된 후 최종적으로 소멸자가 호출된 후 메모리에서 사라지는 형태의 라이프사이클을 가집니다.

장 요약

결론적으로 말해서 소멸자(종료자)는 우리가 직접 사용할 일은 없습니다. 이번 강의는 소멸자의 실행 시점을 살펴보는데 약간의 시간을 투자했고, 가비지 수집기(GC)의 역할을 들어보는걸로 만족합니다. 계속해서 클래스의 핵심 멤버들인 메서드, 속성 등을 학습해 나가도록 하겠습니다.

VisualAcademy Docs의 모든 콘텐츠, 이미지, 동영상의 저작권은 박용준에게 있습니다. 저작권법에 의해 보호를 받는 저작물이므로 무단 전재와 복제를 금합니다. 사이트의 콘텐츠를 복제하여 블로그, 웹사이트 등에 게시할 수 없습니다. 단, 링크와 SNS 공유, Youtube 동영상 공유는 허용합니다. www.VisualAcademy.com
박용준 강사의 모든 동영상 강의는 데브렉에서 독점으로 제공됩니다. www.devlec.com