자동 메모리 관리 시스템. 가비지 컬렉션을 통해 메모리를 관리하는 언어를 Managed Language라고 한다. 메모리 관리로 인한 프로그래머의 실수를 줄여준다는 장점이 있지만, 메모리 참조에 대한 정보를 일정 주기마다 추적하고 관리해야 하기 때문에 성능에 영향을 줄 수 있다.
.NET 기반의 언어는 모두 가비지 컬렉션을 사용한다.
가장 기본적인 형태는 모든 개체의 메모리 참조 여부를 추적하고, 참조되지 않는 개체는 해제하는 형태로 동작한다. 생성된 모든 개체를 확인해야하기 때문에 느릴 수 밖에 없지만, 복잡한 로직 없이 안정적으로 메모리 관리를 할 수 있는 방법이라고 할 수 있다.
.NET 기반 Garbage Collection은 Mark And Sweep 알고리즘을 통해 추적한다고 한다.
Mark And Sweep 단계
1. Root Object로 부터 시작하여 참조 관계가 있는 오브젝트를 탐색하며, 마크한다.
2. 탐색이 끝나면 마크되지 않은 오브젝트를 스윕(메모리 해제)한다.
이는 흔히 코딩테스트에서 나오는 그래프 완전 탐색과 유사하다고 생각할 수 있다.
1. 루트 노드를 시작으로 그래프 완전탐색을 시작, 방문체크를 한다.
2. 방문체크가 되지 않은 노드를 가비지로 정의하고 제거한다.
방문체크를 하기 때문에 순환참조로 인한 무한루프를 걱정할 필요가 없다는 장점이 있다. 이는 c++ 의 shared_ptr을 관리하는 방법인 'RefCount를 활용한 RAII'가 순환참조로 인한 오류가 발생할 수 있다는 점을 생각했을 때, 큰 장점이라고 할 수 있다.
개체를 세대별로 관리하는 것은 Garbage Collection의 성능 향상을 도모하기 위한 로직이다. 프로세스가 실행되는 동안 계속해서 사용할 개체들은 일반적으로 프로세스가 시작됐을때 생성될 가능성이 높고, 오랫동안 존재한 개체들은 계속해서 사용될 가능성이 높다. 반대로 말하면, 최근에 생성된 개체일수록 빨리 해제될 가능성이 높다는 것이다. 이런 생각을 기반으로 인스턴스화된 개체를 생성된 시기에 따라서 세대별로 나누고, 가장 최근에 생성된 세대를 우선적으로 Garbage Collection 하는것이 Generational Garbage Collection이다.
.NET에서는 Generation 0, Generation 1, Generation 2로 나누며, 숫자가 커질수록 오래전에 생성된 세대를 관리한다. Generation 0에서 Garbage Collection을 통해 충분한 메모리가 확보되었다면, 이전 세대에서의 Garbage Collection을 진행하지 않는 방식으로 최적화를 한다.
Garbage Collection을 수행할때는 모든 실행 흐름을 멈추고 Garbage Collection을 가장 우선적으로 처리하게 되는데, 이때 실행 흐름을 강제로 멈추는 것을 Stop The World라고 한다. Stop the world는 GC를 사용하는 언어에게는 피할 수 없는 성능 저하이지만, 이 현상을 최소화 하기 위해 Generational GC등의 여러 최적화 기법을 사용한다.