Programming/.NET

GC는 힙에 할당된 객체의 소멸을 자동으로 처리하여 메모리를 관리합니다. 이때 객체가 할당된 힙메모리의 관리는 세대로 구분하여 처리하게 됩니다.

 

예를 들어

static void Main(string[] args)
{
    MyClass m = new MyClass();

    Console.WriteLine(GC.GetGeneration(m));
}

위에서 처럼 new를 통해 최초로 개체를 생성하면 이 개체는 0세대로 분류됩니다. 참고로 GC의 GetGeneration메서드를 사용하면 특정 개체의 세대를 확인할 수 있습니다.

 

이렇게 프로그램 내에서 생성되는 참조형식의 개체들은 0세대로 분류해 계속 힙메모리를 할당하다가 어느정도 용량이 커지게 되면 GC가 자동으로 실행되어 현재 0세대중 사용되지 않는 개체를 골라내어 소멸처리하게 됩니다. GC가 개체의 사용유무를 확인하는 방법은 스택에 개체가 할당된 힙의 주소가 있는지 또는 다른 개체에서 참조하고 있는지의 여부입니다. 이런것들을 루트참조라고 하는데 이 루트참조가 없으면 개체를 메모리에서 제거하게 됩니다.

static void Main(string[] args)
{
    MyClass m = new MyClass();
    MyClass m2 = new MyClass();

    m = null;

    GC.Collect();

    Console.WriteLine(GC.GetGeneration(m2));
}

예제에서 처음 개체 m은 생성후 null을 할당해 스택의 주소를 제거하도록 하였습니다. 그런 후 GC를 실행하면 m은 소멸되고 m2만 남게 되는데 GC의 실행으로 남은 m2는 1세대로 올라가게 됩니다. GC가 세대를 구분하는 기준은 현재 힙공간을 가리키고 있는 내부 포인터의 위치입니다.

 

개체를 힙공간에 할당하기전 최초 포인터는 0세대로 정해지는데 개체를 생성할때마다 힙공간에 개체에 필요한 용량을 할당하게 되고 포인터는 그 주소만큼 증가하여 다음 힙공간을 가리키게 됩니다. 그러다가 일정 용량이상이 커지거나 Collect()메서드호출등의 이유로 GC가 실행되면 지금 현재 포인터가 가리키고 있는 주소부터 그 이전까지 할당된 힙공간을 모두 기존의 0세대에서 1세대로 변경하는 방식으로 세대를 증가시키게 됩니다. 증가하는 세대수는 2세대가 최대이며 2세대 부터는 메모리를 계속 점유하면서 남아있게 됩니다.

 

GC가 세대를 구분하는 이유는 GC동작의 효휼성 때문입니다. GC가 동작할때마다 전세대를 대상으로 한다면 GC입장에서는 부담이 아닐 수 없습니다. 그래서 처음에는 0세대만을 대상으로 GC를 수행하다가 메모리 부족현상이 발생하면 0과 1세대를 대상으로 GC가 동작하게 됩니다. 그러다가 다시 메모리 부족이 발생하면 2세대를 포함한 모든 세대를 대상으로 GC가 수행됩니다. 예제에서 Collect() 메서드를 호출해 GC의 동작을 평가하고 있는데 이때 메서드호출시 0 이나 1 또는 2값을 매개변수로 전달하면 해당 세대에 대해서만 GC가 동작되도록 지정할 수 있습니다.

 

그런데 이 과정에서 특정 개체가 메모리에서 소멸하게 되면 개체가 소멸된 힙공간은 비어있게 되는데 GC는 이를 그대로 두지 않고 뒤에 있는 개체를 당겨와 비어있는 공간을 메우게 됩니다. 그래서 개체가 최초로 생성될때의 메모리 주소와 GC가 실행되고 난 이후의 메모리 주소는 달라질 수 있습니다. 하지만 꼭 그렇지 않은 경우도 있습니다. 용량이 너무 큰 개체(85,000 Byte)의 경우에는 그 개체에 할당된 힙을 LOH(Large Object Heap)로 분류하고 위치를 고정시키는데 너무 큰 개체를 GC가 동작할때마다 메모리 내부에서 이동시키기에는 부담이 너무 크기 때문입니다. LOH는 시작부터 2세대로 들어가며 메모리 위치를 바꾸지 않기에 메모리에 공백이 생길수도 있어서 주의해야 합니다.

 

참고로 GC의 Collect() 메서드는 GC를 수행하는 메서드인데 이 메서드를 호출한다고 해서 무조건 GC가 수행되지는 않고 실제 GC가 필요한지는 CLR이 판단하여 수행여부를 결정합니다.

'Programming > .NET' 카테고리의 다른 글

[C#] Stopwatch  (0) 2019.05.09
가비지 수집기 : GC (Garbage Collector)  (0) 2019.04.30
[C#] null 조건  (0) 2019.04.16
[ASP.NET] 인증및 접근제어와 로그인  (0) 2019.04.11
[C#] yield  (0) 2019.04.02
[C#] params  (0) 2019.03.19
0 0