본문 바로가기
컴퓨터/C#

[C#] 객체와 생성

by Luyin 2013. 5. 28.

객체와 메모리

* 객체 생존 기간
객체는 new 연산자에 의해 메모리를 할당 하고 생성자에 의해 메모리에 있는 객체가 초기화 되는 것입니다. 반대로 소멸되는 경우에는 먼저 Finalize 메소드를 이용하여 메모리를 초기화 되지 않은 상태로 돌리며 다음으로 이메모리 공간을 Heap에 반환하는 것입니다. 그러므로 객체의 존속기는 new를 이용하여 메모리를 할당받는 순간부터 메모리를 Heap에 반환 할 때 까지라고 보면 되겠습니다.

* 객체와 영역
int나 struct와 같이 Stack에 존재하는 Value Type 변수들은 범위를 벗어나면 사라지므로 존재 기간이 짧습니다. 그러나 Heap에 있는 객체(Reference Type)들인 경우 영역을 벗어 나더라도 메모리를 해제 할때까지 사라지지 않는 것이 특징 입니다.

* GC(Garbage Collector)
C#의 경우 기존의 C/C++ 처럼(new, delete) 프로그래머가 메모리 관리를 하지 않아도 되게 설계가 됭 있습니다.(자바와 비슷하죠^^;;;) CLR에서 자동으로 알아서소멸 시켜 줍니다. 또한 C#의 경우 명시적으로 코드상에서 객체를 소멸 할 수 없는 대신 Garbage Collector라는 것을 지원 해 줍니다. Garbage Collector는 메모리에 있는 참조가 끝난 객체를 쓰레기 치우는 것처럼 소멸 시키는 역할을 하는 것인데 메모리가 부족 하다고 판단이 들면 Garbage Collector는 참조되는 않는 객체의 메모리 영역을 청소하여 Heap에 반환 하는 것입니다. 또한 Garbage Collector는 객체를 오직 한번만 제거해 버리며 참조되고 있지 않은 것들만 제거를 합니다.(만약에 참조되고 있는 객체를 쓰레긴줄 알고 버리면 큰일 나겠죠???). 프로그래머가 일일이 코드를 통해 기술 했을때의 문제인 객체를 반복해서 소멸 한다든지, 참조되고 있는 객체를 소멸한다든지 하는것은 막아 주는 것입니다. 코딩 상에서 Garbage Collector에게 명시적으로 객체를 소멸 시켜달라고 할 수 있으나 그것은 객체를 소멸 시켜도 된다는 것을 알리는 역할을 할 뿐이지 즉시 작동 하는 것은 아닙니다.

* 소멸자의 사용
- Finalize 메소드
객체가 Garbage Collector에 의해 소멸되는 시점에 호출되는 함수 이다. 이곳에 파일을 닫는 다든지, DB접속을 종료 한다든지 하는 일들을 명시 할 수 있습니다. Finalize 메소드를 구현 하면 C# 컴파일러가 컴파일시 finalization Queue에 이 객체가 등록되고 Garbage Collector가 작동되면 객체를 소멸하기 전에 Finalize 메소드를 호출되는 것입니다.

- 소멸자 사용방법
Finalize 메소드 대신에 소멸자(~생성자)를 이용 할 수 있으며 컴파일을 하게 되면 소멸자를 Finalize 메소드로 바꾸어 놓게 됩니다. 즉 C#에서 소멸자와 Finalize 메소드는 같은 의미라고 보면 됩니다. 소멸자의 경우 항상 접근권한이 public이 되어야 하므로 별도로 접근 지시자를 지정하지 못하도록 되어 있습니다. 또한 매개변수도 받을 수 없습니다.

* System.CG 클래스
Garbage Collector가 작동 하기 전에 리소스를 해제 할려고 하면 어떻게 할까?... 이경우 IDisposal 인터페이스의 Dispose 메소드를 구현해 주고 사용자가 이메소드를 호출하면 직접 리소스를 해제 할 수 있습니다. 물론 Disposal 메소드안에 리소스를 정리하는 코드를 기술하면 되는거죠... 만약 리소스를 해제 하는 코드가 소멸자에도 있고 Dispoase에도 있으면 코드가 중복되게 되는데... 소멸자에서도 Dispose 메소드를 호출 함으로서 리소스의 해제가 가능 합니다. 만약 Dispose 메소드를 이용하여 리소스를 해제 하였다면 Finalize 메스에서는 리소스를 해제 하지 않아도 되는데 이런경우 System.GC 클래스의 SuppressFinalize 메소드를 호출하여 Finalize 메소드가 호출되지 않게 설정 할 수 있다. 결국 아래의 소스와 같은 구조가 되는 것이다.

using System; 
class Test : IDisposable { 
    private bool isDispose = false; 
    ... 
    ~Test() { 
        if (!isDispose) { 
            Dispose(); 
        } 
    } 

    public void Dispose() { 
        isDispose = true; 
        // 이 부분에서 리소스를 정리 한다. 
        // 참고로 GC.Collect() 메소드는 Garbage Collector가 Finalize를 호출하게 하는 메소드 이다. 
        GC.SuppressFinalize(this); //Finalize 메소드를 소멸자에서 호출 안하도록 설정 
    } 
} 

[예제]
using System; 
class Garbage : IDisposable 
{ 
    private bool isDispose = false; 
    private string name; 

    public Garbage(string name) 
    { 
        this.name = name; 
        Console.WriteLine("{0}객체 생성됨...", this.name); 
    } 

    ~Garbage() 
    { 
        if (!isDispose) 
        { 
            Dispose(); 
        } 
    } 

    public void Dispose() 
    { 
        isDispose = true; 
        //... 리소스를 해제함... 
        Console.WriteLine("{0}객체의 리소스 해제 OK...", name); 
        GC.SuppressFinalize(this); 
    } 
} 

class GarbageTest1 
{ 
    static void Main() 
    { 
        Garbage g1 = new Garbage("1번객체"); 
        Garbage g2 = new Garbage("2번객체"); 
        Garbage g3 = new Garbage("3번객체"); 
        Garbage g4 = new Garbage("4번객체"); 

        g1.Dispose(); 
        GC.SuppressFinalize(g2); 
    } 
}
[결과]
1번객체객체 생성됨...
2번객체객체 생성됨...
3번객체객체 생성됨...
4번객체객체 생성됨...
1번객체객체의 리소스 해제 OK...
4번객체객체의 리소스 해제 OK...
3번객체객체의 리소스 해제 OK...