[C#] 세대별 가비지 콜렉션 (GC, Garbage Collection)

Date:     Updated:

카테고리:

태그:

이 글은 C#의 세대별 가비지 콜렉션을 공부하고 요약한 글이다
참고 글 : https://learn.microsoft.com/ko-kr/dotnet/standard/garbage-collection/fundamentals

간단 요약

  • 가비지 콜렉션은 애플리케이션의 메모리 할당 및 해제를 관리해 준다
  • 메모리 해제를 잊어서 메모리 누수가 발행하는 문제를 방지 할 수 있다
  • 메모리 할당은 관리되는 힙에 할당된다
  • 사용되지 않는 개체를 가비지 콜렉션이 찾아서 해제를 진행한다
  • 가비지 콜렉션의 성능을 최적화하기 위해 관리되는 힙은 총 3개의 세대로 나뉘어져 있다

가비지 콜렉션이란?

  • 애플리케이션의 메모리 할당 및 해제를 관리
  • 따라서 개발자가 메모리 관리 작업을 따로 작성할 필요가 없다
  • 메모리 해제를 잊어서 메모리 누수가 발행하는 문제를 방지 할 수 있다

이점

  • 개발자가 수동으로 메모리를 해제할 필요가 없다
  • 관리되는 힙에 효율적으로 개체를 할당
  • 더 이상 사용되지 개체를 회수하여 메모리를 확보
  • 개체가 다른 개체에 할당된 메모리 자체를 사용할 수 없도록 하여 메모리 보안을 제공

메모리 할당

  • 사용자가 새 프로세스를 시작하면 런타임에서는 인접한 주소 공간 영역을 이 프로세스에 예약합니다
  • 이 예약된 주소 공간을 관리되는 힙이라고 합니다
  • 모든 참조 형식(Reference Type)은 관리되는 힙에 할당
  • 관리되는 힙에서 메모리를 할당하면 관리되지 않는 힙에서 메모리를 할당하는 것보다 속도가 더 빠르다
  • 런타임에서는 포인터에 값을 더하여 개체에 메모리를 할당하기 때문에, 스택에서 메모리를 할당하는 속도만큼 빠르다

메모리 해제

  • 수집을 수행할 때 가비지 콜렉션은 프로그램에서 더 이상 사용되지 않는 개체에 대한 메모리를 해제한다
  • 가비지 콜렉션은 프로그램의 루트를 검사하여 더 이상 사용되지 않는 개체를 결정
    • 애플리케이션 루트에 포함되는 항목 : 정적 필드, 스레드 스택의 지역 변수, CPU 레지스터, GC 핸들, finallize 큐
  • 각 루트는 관리되는 힙에 있는 개체를 참조하거나 Null로 설정
  • 가비지 콜렉션은 이 목록을 사용하여 루트에서 연결할 수 있는 모든 개체를 포함하는 그래프를 만든다
  • 그래프에 없는 개체는 애플리케이션의 루트에서 연결할 수 없는 상태임으로 가비지(수집해야 할 항목)로 간주하고 이 개체에 할당된 메모리를 해제할 것이다
  • 수집을 수행할 때 가비지 콜렉션은 연결할 수 없는 개체에서 사용되는 주소 공간 블록을 찾기 위해 관리되는 힙을 검사한다
  • 연결할 수 없는 개체가 발견되면 가비지 콜렉션은 개체를 해제시키고 연결할 수 있는 메모리를 압축한다
  • 가비지 콜렉션은 연결할 수 없는 개체의 수가 엄청나게 발견되는 경우에만 메모리를 압축한다
  • 런타임에서는 성능 향상을 위해 큰 개체의 메모리를 별도의 힙에 할당한다

가비지 수집 조건

  • 다음 조건 중 하나가 충족될 경우 수집을 수행한다
    • 시스템의 실제 메모리가 부족한 경우
    • 관리되는 힙의 할당된 개체에 사용되는 메모리가 허용되는 임계값을 초과하는 경우
    • GC.Collect 메서드가 호출되는 경우

관리되는 힙

  • CLR(Common Language Runtime)은 가비지 콜렉션을 초기화한 후 개체를 정하고 관리할 메모리 세그먼트를 할당하며, 이 메모리를 관리되는 힙이라고 한다
  • 관리되는 각 프로세스에 대해 관리되는 힙이 있다
  • 프로세스의 모든 스레드는 같은 힙에 개체 메모리를 할당한다
  • 힙에 할당되는 개체의 수가 적을수록 가비지 콜렉션이 할 일도 줄어든다
    • 그래서 개체를 할당할 때는 15바이트만 필요한 상황에서 32바이트 배열을 할당하는 것처럼 필요 이상의 값을 사용하지 마세요

세대

  • GC 알고리즘은 몇 가지 고려 사항을 기반으로 한다
    • 가비지 콜렉션은 관리되는 전체 힙보다 일부 힙에서 더 빠르게 메모리를 압축할 수 있다
    • 최신 개체는 수명이 짧고 이전 개체의 수명은 더 깁니다
    • 새로운 개체일수록 서로 연결되는 경향이 있어서 애플리케이션에서 거의 동시에 액세스 됩니다
  • 가비지 콜렉션은 주로 수명이 짧은 개체의 회수와 함께 발생합니다
  • 가비지 콜렉션의 성능을 최적화하기 위해 관리되는 힙은 0세대, 1세대, 2세대의 3개 세대로 나뉘어 있으므로 수명이 길고 수명이 짧은 개체를 별도로 처리할 수 있습니다
  • 가비지 콜렉셔은 새 개체를 0세대에 저장한다
  • 애플리케이션 수명의 초기에 만들어져 수집 후에도 남아 있는 개체는 수준이 올라 1세대와 2세대에 저장된다
  • 전체 힙보다 일부 관리되는 힙을 압축하는 것이 더 빠르기 때문에 가비지 수집기는 수집을 수행할 때마다 이 체계를 사용하여 전체 관리되는 힙에서 메모리를 해제하는 대신 특정 세대에서 메모리를 해제할 수 있습니다

0세대

  • 가장 젊고 수명이 짧은 개체를 포함한다
  • 수명이 짧은 개체의 예로는 임시 변수가 있다
  • 가비지 콜렉션은 이 세대에서 가장 자주 발생한다
  • 새로 할당된 개체는 0세대에 저장되지만 큰 개체의 경우는 LOH(Large Object Heap)으로 이동한다

1세대

  • 수명이 짧은 개체를 포함하고 수명이 짧은 개체와 수명이 긴 개체 사이의 버퍼 역할을 한다
  • 0세대 수집을 수행한 후 연결할 수 있는 개체의 메모리를 압축하고 1세대로 승격시킨다
  • 수집 후에도 존재하는 개체는 수명이 긴 성향이 있기 때문에, 이런 개체를 상위 세대로 승격시키는 것은 당연하다
  • 가비지 콜렉션은 0세대 수집을 수행할 때마다 1세대와 2세대에서 개체를 다시 검사할 필요가 없다
  • 0세대 수집이 애플리케이션에서 새 개체를 만들기에 충분한 메모리를 회수하지 못하는 경우 가비지 수집기는 1세대 및 2세대의 수집을 수행할 수 있다

2세대

  • 수명이 긴 개체가 포함되어 있다
  • 수명이 긴 개체의 예로는 프로세스의 기간 동안 유지되는 정적 데이터가 포함된 서버 애플리케이션의 개체가 있습니다
  • 가비지 콜렉션에서 유지되는 2세대 개체는 이후 수집에서 연결할 수 없다고 판단될 때까지 2세대에 남아 있는다
  • LOH(Large Object Heap)의 객체는 2세대에서도 수집된다

세대 결론

  • 가비지 콜렉션은 조건이 보증하는 특정 세대에서 발생한다
  • 하나의 세대를 수집한다는 것은 해당 세대와 그보다 더 젊은 모든 세대의 개체를 수집한다는 것을 의미한다
  • 2세대 가비지 수집은 모든 세대(즉, 관리되는 힙의 모든 개체)에서 개체를 회수하기 때문에 전체 가비지 수집이라고도 합니다

가비지 수집

  • 가비지 수집은 다음 단계로 구성됨
    • 모든 활성 개체를 찾아 목록을 만드는 표시 단계
    • 압축될 개체에 대한 참조를 업데이트하는 재배치 단계
    • 비활성 개체에 의해 점유된 공간을 회수하고 남은 개체를 압축하는 압축 단계
  • 가비지 수집이 시작되기 전에 가비지 수집을 진행하는 스레드를 제외한 모든 관리되는 스레드가 일시 중단된다


💻 열심히 공부해서 작성 중이니 오류나 틀린 부분이 있을 경우 
  언제든지 댓글 혹은 메일로 알려주시면 감사하겠습니다! 😸

맨 위로 이동하기

CSharp 카테고리 내 다른 글 보러가기

댓글 남기기