[C#] 세대별 가비지 콜렉션 (GC, Garbage Collection)
카테고리: CSharp
이 글은 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세대 가비지 수집은 모든 세대(즉, 관리되는 힙의 모든 개체)에서 개체를 회수하기 때문에 전체 가비지 수집이라고도 합니다
가비지 수집
- 가비지 수집은 다음 단계로 구성됨
- 모든 활성 개체를 찾아 목록을 만드는 표시 단계
- 압축될 개체에 대한 참조를 업데이트하는 재배치 단계
- 비활성 개체에 의해 점유된 공간을 회수하고 남은 개체를 압축하는 압축 단계
- 가비지 수집이 시작되기 전에 가비지 수집을 진행하는 스레드를 제외한 모든 관리되는 스레드가 일시 중단된다
💻 열심히 공부해서 작성 중이니 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 알려주시면 감사하겠습니다! 😸
댓글 남기기