프로그래밍/C#

.NET의 가비지 컬렉터(GC, Garbage Collection)

argentdarae 2025. 3. 20. 17:49
반응형

GC의 존재 이유

애플리케이션의 Heap 메모리 할당 및 해제를 관리한다. 개발자는 GC로 인해 다양한 이점을 얻을 수 있다

  • 개발자가 수동으로 메모리를 해제할 필요가 없다. 메모리가 부족하거나 일정 주기마다 가비지 컬렉션(Garbage Collection)을 진행한다
  • 세대 기반 관리를 통해 최근 생성된 객체를 먼저 정리하여 성능을 최적화한다
  • 사용할 수 있는 메모리 블록을 찾을 수 없는 경우, 메모리 압축이 일어나 메모리 파편화를 방지한다. 이 때 LOH는 속성을 설정하지 않으면 압축되지 않는다
  • 항상 객체를 통해 메모리를 사용하므로 메모리 안정성을 제공한다. C나 C++처럼 개발자가 임의의 주소 값을 직접 참조하거나 변경할 수 없기 때문이다

 

GC의 동작 조건

  • 시스템의 실제 메모리가 부족할 경우. 여러 프로세스가 동시에 실행되면서 사용 가능한 물리 메모리가 부족하면 GC가 동작한다
  • 관리되는 힙의 할당된 객체에 사용되는 메모리가 허용되는 임계값을 초과할 때. 각 세대마다 GC가 실행되는 기준이 되는 메모리 용량 한계값이 존재하며 이를 임계값이라 한다
  • GC.Collect 메서드가 호출될 때. 이 메서드는 주로 테스트에 사용된다

 

GC의 동작 과정

가비지 컬렉션은 다음 단계로 수행된다

1. 표시(Marking)

유효 객체와 불필요한 객체를 구분하는 과정이다

GC는 어플리케이션에서 참조되고 있는 객체 목록을 수집하고, 이 과정에서 판별이 이루어진다

2. 재배치(Relocation)

압축될 객체에 대한 참조를 업데이트 하는 과정이다

정리할 객체를 제외하고 남아 있는 객체의 메모리 주소 조정이 이루어진다. 기존 객체들이 새로운 위치로 이동하면서, 기존의 메모리 공간을 정리할 준비도 한다

3. 압축(Compaction)

사용되지 않는 메모리를 회수하고, 남은 객체를 정리한다

이 때 GC는 정리된 객체가 차지했던 메모리를 해제하고 살아남은 객체들을 한쪽으로 모아 단편화를 방지한다

 

GC가 정리해야 할 객체를 판별하는 방법 (Mark-and-Sweap)

GC는 다음의 세 가지 Root 정보를 이용하여 객체가 살아있는 지 판단한다

1. 스택 루트 (Stack Roots)

실행 중인 함수의 지역 변수 및 매개변수에서 객체를 참조하고 있는지 확인한다

2. 가비지 수집 핸들 (GC Handle)

.NET에서 런타임이나 사용자가 직접 지정한 핸들에 등록된 객체들은 활성화되어 있다 판단한다

3. 정적 데이터

어플리케이션 도메인이 정적 객체를 추적한다. 정적 변수는 GC의 수집 대상이 아니다

 

GC 실행 시 스레드 처리

가비지 컬렉션이 시작되면 GC를 트리거한 스레드를 제외한 모든 관리되는 스레드가 일시 중단된다

즉, 멀티스레드 환경에서도 GC가 실행되는 동안은 모든 스레드가 동작하지 않는 것이다. GC가 최대한 덜 동작하게 만드는 이유도 이것이다

 


Reference

가비지 컬렉션 기본 사항 - MSDN