Garbage Collector

[C#] Garbage Collector 란?

Garbage Collector란 가비지 컬렉터라고 하며 GC라고 부르기도 합니다.

GC는 CLR(공용 언어 런타임)에서 제공하는 자동 메모리 관리 소프트웨어입니다.

C#으로 작성한 소스 코드를 컴파일해서 실행 파일을 만들고 실행하면,

CLR은 프로그램을 위해 메모리를 확보합니다.

메모리의 공간을 확보해서 관리되는 힙 메모리를 마련합니다.

힙 메모리의 첫 번째 주소에 다음 객체를 할당할 메모리의 포인터를 위치시킵니다.

각 프로세스는 가상주소공간을 포함합니다.

이 때, 가상 주소 공간은 조각화될 수 있는데

가비지 컬렉터는 객체를 할당할 수 있는 블록을 찾게 됩니다.


GC가 메모리를 관리하는 방법

데이터가 할당된 메모리의 위치를 참조하는 객체를 루트라고 합니다.

JIT 컴파일러는 이 루트들을 그래프로 만들고 CLR은 루트 목록을 관리하며 상태를 갱신하다.

애플리케이션 루트에는 정적 필드, 스레드 스택의 지역 변수, CPU 레지스터, GC핸들, finalize 큐가 포함됩니다.

GC는 루트목록을 참조하며 힙을 차지하고 있는 쓰레기(힙 메모리를 차지하고 있으나 이를 참조하는 데이터가 없는 개체)들을 수집합니다.


GC 동작 순서

  1. 작업을 진행하기 전, GC는 모든 객체가 쓰레기라고 가정합니다.
루트 목록은 그래프로 관리를 하니, 그래프에 없는 개체라고 생각하시면 됩니다.

  1. 루트 목록 내 어떤 루트도 메모리를 가리키지 않는다고 가정합니다.

  2. 루트 목록을 순회하면서 각 루트가 참조하고 있는 힙 개체와의 관계 여부를 조사합니다.

  3. 어떤 루트와도 관계가 없는 힙의 개체들은 쓰레기로 간주합니다.

  4. 쓰레기 개체가 가지고 있던 메모리는 이제 비어 있는 공간이 됩니다.

  5. 비어 있는 공간에 개체를 이동시켜 채워넣습니다.


GC 메모리 정리 순서

  1. 가비지 컬렉터는 메모리를 할당하고 있는 개체들을 3개의 세대로 나눕니다. (0세대, 1세대, 2세대)

  2. 0세대는 나이가 적은 개체, 2세대는 나이가 많은 데이터를
    위치시킵니다.

나이는 가비지 컬렉션을 겪은 횟수로 정해집니다.

  1. 가비지 컬렉터는 0세대를 위주로 개체 회수를 진행합니다.

0세대에서 개체가 회수되지 않았다면 다음 세대로 넘어가게 됩니다.


GC 호출 시기

  1. 엔진은 수집을 수행하기에 가장 적합한 시간을 결정하고, 시간에 맞춰 주기적으로 GC를 호출합니다.

  2. 시스템의 실제 메모리가 부족한 경우 호출합니다.

  3. 할당된 개체에 사용되는 힙 메모리가 허용하는 임계값을 초과한 경우 호출합니다. (3개의 세대 중 한 세대의 잔존율이 높을 경우 해당 세대의 할당 임계값을 늘립니다.)

  4. GC.Collect 메소드를 호출하여 호출하기도 하지만 GC는 주기적으로 호출되므로 수동으로 호출할 필요는 없습니다.

GC 수행 작업

  1. 모든 활성 개체를 찾아 루트 목록을 만드는 표시 작업

  2. 압축될 개체에 대한 참조를 업데이트 하는 재배치 작업

  3. 비활성 개체에 의해 점유된 공간을 회수하고 남은 개체를 압축하는 압축작업