C# 가비지컬렉터

김현승·2024년 4월 27일
0

C#

목록 보기
3/13

C#에서 가비지 컬렉터(Garbage Collector, GC)는 .NET 프레임워크의 중요한 컴포넌트로, 자동으로 메모리 관리를 수행합니다. 가비지 컬렉터는 개발자가 명시적으로 메모리를 해제하지 않아도 되도록 설계되었으며, 사용되지 않는 객체의 메모리를 자동으로 회수합니다. 이 메커니즘은 메모리 누수를 방지하고, 프로그램의 안정성과 성능을 향상시키는 데 기여합니다.

가비지 컬렉터의 작동 원리

가비지 컬렉터는 "mark and sweep" 알고리즘을 기반으로 작동합니다. 주요 과정은 다음과 같습니다:

  1. 마킹(Marking): 가비지 컬렉터는 루트 집합(Root Set)에서 시작하여 접근 가능한 모든 객체를 탐색하고 표시합니다. 루트 집합은 스택, 정적 영역, 애플리케이션 코드에서 직접 참조되는 객체들로 구성됩니다.
  2. 스위핑(Sweeping): 마킹 과정에서 표시되지 않은 객체들은 접근할 수 없는 객체로 간주되며, 이들 객체가 차지하고 있는 메모리는 해제됩니다.

가비지 컬렉터의 세대

.NET의 가비지 컬렉터는 세대별 수집(Generational Collection) 방식을 사용하여 효율성을 높입니다. 객체들은 세대에 따라 분류되며, 객체의 수명이 길어질수록 높은 세대로 이동합니다. 세대는 다음과 같이 분류됩니다:

  • 세대 0(Generation 0): 새로 생성된 객체들이 위치하는 세대입니다. 이 세대의 가비지 컬렉션이 가장 자주 발생하며, 가장 짧은 수명을 가진 객체들을 대상으로 합니다.
  • 세대 1(Generation 1): 세대 0에서 살아남은 객체들이 이동하는 세대입니다. 세대 0의 컬렉션에서 살아남은 객체들은 세대 1로 승격됩니다. 이 세대는 버퍼 세대로, 세대 0과 세대 2 사이에서 중간 단계를 제공합니다.
  • 세대 2(Generation 2): 세대 1에서 살아남은 객체들이 이동하는 가장 높은 세대입니다. 이 세대의 객체들은 가장 오래 살아남은 것으로 간주되며, 가비지 컬렉션이 가장 적게 발생합니다.

가비지 컬렉터의 성능 고려 사항

가비지 컬렉터는 편리하고 효과적인 메모리 관리를 제공하지만, 가비지 컬렉션 과정에서 애플리케이션의 실행이 일시 중단될 수 있습니다. 이러한 "Stop-the-world" 중단은 가비지 컬렉션 중 모든 애플리케이션 스레드가 일시 정지되는 현상입니다. 따라서 효율적인 메모리 사용과 객체 할당 전략은 가비지 컬렉션의 빈도와 영향을 최소화하는 데 중요합니다.

최적화 팁

  • 가능한 한 작은 객체를 사용하고, 필요 이상으로 대규모 객체를 생성하지 않아야 합니다.
  • 장기간 사용되는 객체는 가능한 한 적게 할당하며, 객체의 승격을 최소화해야 합니다.

.Net GC와 Unity GC의 차이

내부적으로 GC의 알고리즘은 Mark and Sweep를 기반으로 하게 되는데 그 이후의 과정이 다르게 됩니다.

.Net에서는 0~2세대까지 총 3개의 세대를 통해서 관리를 하게 됩니다.

유니티에서는 Boehm-Demers-Weiser 라는 알고리즘을 통해 GC 작업을 하게 됩니다. Mark and Sweep인것은 같으나 세대 구분이 없고 메모리 정렬도 없습니다. 때문에 19 버전 이상에서 제공하게 되는 점진적 GC 작업을 활용하거나 오브젝트 풀링 등의 기법을 활용해서 최대한 최적화를 해줘야 할 필요가 있습니다.

상호 참조 문제

만일 C#에서 두 객체가 서로 참조중이라 하더라도 외부에서 참조가 없어 Mark 되지 않는다면 Sweep 단계에서 해제되게 됩니다.

0개의 댓글