.NET에서의 GC와 작동 원리

.NET 프레임워크에서 Garbage Collection(GC)은 메모리 관리를 자동화하는 핵심 요소입니다. 개발자는 메모리 할당과 해제를 명시적으로 처리할 필요 없이, GC가 객체의 생명 주기를 관리하고 메모리를 효율적으로 회수합니다. 이번 글에서는 .NET에서의 GC 특징과 작동 원리를 알아보겠습니다.

.NET의 GC 특징

.NET의 GC는 성능 최적화와 메모리 관리 효율성을 높이기 위해 여러 가지 고유한 기능을 제공합니다.

세대별 가비지 컬렉션(Generational Garbage Collection)

객체의 수명 주기에 따라 메모리를 관리하기 위해 세대별 가비지 컬렉션 방식을 채택합니다. 이는 객체를 생성 시점과 생존 기간에 따라 세 개의 세대로 구분하여 관리합니다.

  • Gen 0: 새로 생성된 객체가 할당되는 영역으로, 수명이 짧은 객체를 관리합니다.
  • Gen 1: Gen 0 수집 과정에서 생존한 객체가 승격되는 영역으로, 중간 수명의 객체를 관리합니다.
  • Gen 2: 장기간 생존하는 객체를 관리하는 영역으로, 가장 낮은 수집 빈도를 가집니다. 이러한 세대별 관리는 대부분의 객체가 짧은 수명을 가진다는 관찰에 기반하여 설계되었습니다. 이를 통해 가비지 컬렉션의 효율성을 높이고, 메모리 회수 작업의 성능을 향상시킵니다.

다양한 GC 모드 지원

애플리케이션의 특성에 맞게 GC의 동작 방식을 선택할 수 있도록 두 가지 모드를 제공합니다.

  • Workstation GC: 데스크톱 애플리케이션에 적합하며, 응답성을 우선시합니다.
  • Server GC: 서버 애플리케이션에 적합하며, 멀티코어 프로세서를 활용하여 병렬로 가비지 컬렉션을 수행합니다. GC 모드를 적절히 선택하면 애플리케이션의 성능과 응답성을 최적화할 수 있습니다.

Large Object Heap(LOH) 관리

큰 객체(85,000바이트 이상)는 Large Object Heap(LOH)에 할당됩니다. LOH는 일반 힙과 별도로 관리되며, 큰 객체의 메모리 할당과 해제에 특화되어 있습니다. LOH는 메모리 파편화를 줄이고 성능을 향상시키는 데 도움을 줍니다.

GC의 작동 과정

GC는 메모리를 효율적으로 관리하기 위해 다음과 같은 단계를 거칩니다.

1. 객체 할당

객체를 생성하면 메모리가 힙에 할당됩니다. .NET은 힙 메모리를 관리 힙(Managed Heap)으로 관리하며, 여기에 모든 참조형 객체가 저장됩니다.

// 객체 생성 예시
string message = "Hello, World!";

2. 객체 참조 추적

GC는 루트(Root)에서 시작하여 객체 그래프를 탐색하면서 도달 가능한 객체를 식별합니다. 루트에는 스택 변수, 전역 변수, CPU 레지스터 등이 포함됩니다. 이 과정을 통해 활성 객체와 가비지 객체를 구분합니다.

3. 가비지 컬렉션 수행

도달 불가능한 객체는 메모리에서 해제됩니다. 가비지 컬렉션은 다음의 단계를 따릅니다.

  • 마킹(Marking): 도달 가능한 객체를 식별하고 표시합니다.
  • 스위핑(Sweeping): 마킹되지 않은 객체를 해제합니다.
  • 컴팩션(Compaction): 메모리 파편화를 방지하기 위해 남은 객체들을 한쪽으로 모읍니다.

4. 세대별 수집

세대별로 가비지 컬렉션이 수행되며, 낮은 세대부터 우선적으로 수집됩니다. 이는 수명이 짧은 객체를 빠르게 회수하여 메모리 효율을 높이는 데 기여합니다.

세대별 가비지 컬렉션의 원리와 이점

Gen 0

  • 가장 빈번하게 수집되는 영역입니다.
  • 수명이 짧은 임시 객체를 관리합니다.
  • 수집 후 생존한 객체는 Gen 1으로 승격됩니다.

Gen 1

  • 중간 정도의 수명을 가진 객체를 관리합니다.
  • Gen 0보다 수집 빈도가 낮습니다.
  • 수집 후 생존한 객체는 Gen 2로 승격됩니다.

Gen 2

  • 장기간 생존하는 객체를 관리합니다.
  • 가장 낮은 수집 빈도를 가지며, 전체 힙의 메모리 누수를 감지하는 데 중요합니다. 이러한 세대별 관리는 가비지 컬렉션의 효율성을 높이고, 메모리 회수 작업에 필요한 시간을 줄이는 데 도움이 됩니다.

.NET GC의 장단점

장점

  • 효율적인 메모리 관리: 세대별 수집을 통해 메모리 사용을 최적화합니다.
  • 유연한 설정 가능: GC 모드를 통해 애플리케이션 특성에 맞는 메모리 관리가 가능합니다.
  • 자동 메모리 회수: 개발자가 메모리 해제에 신경 쓰지 않아도 됩니다.

단점

  • Stop-the-world 현상: 가비지 컬렉션 시 애플리케이션이 일시적으로 중단될 수 있습니다.
  • LOH 파편화 문제: 큰 객체의 빈번한 할당과 해제로 메모리 파편화가 발생할 수 있습니다.
  • 복잡한 튜닝 필요: 최적의 성능을 위해 GC 설정과 메모리 관리를 세밀하게 조정해야 할 수 있습니다.

결론

.NET의 GC는 메모리 관리를 자동화하고 최적화하기 위한 다양한 기능을 제공합니다. 세대별 가비지 컬렉션, 다양한 GC 모드, LOH 관리 등을 통해 개발자는 안정적이고 효율적인 애플리케이션을 개발할 수 있습니다. 그러나 GC의 작동 원리와 특징을 이해하고 적절히 활용하는 것이 성능 최적화에 중요합니다.