본문 바로가기
카테고리 없음

[C#] Garbage Collector(가비지 컬렉터)

by 은유지니 2025. 2. 10.

내가 이해한대로 쭉 써보려고 한다. 정리는 언젠가...

일단 가비지 컬렉터는  Java와 C# 에서 자동으로 메모리를 관리해준다. C/C++에서 프로그래머가 직접 관리를 해야하는거에 비해 아주 편리한 기능이다.
하지만 GC가 너무 자주 발생해도 성능에 문제가 생기니, 실행되는 시점이나 상황들을 잘 알아 놓아야 효율적인 프로그래밍을 할 수 있다.


일단 GC를 이해하기 위해서는 Value Type과 Reference Type을 알아야한다.

  • Value Type : Stack에 할당됨
    ex) int, float, double, bool, char, enum, struct
  • Referece Type : Heap에 데이터가 저장되고, Stack에서는 그의 주소값을 할당함.
    ex) string, array, class, interface, delegate, object, ref가 붙은 value type

여기서 struct가 value Type이라는 것과, int[]같은 array는 Reference Type이라는 것은 혼동에 주의한다.

Value타입은 지역변수로 선언될때 Stack에 할당됐다가, 메서드의 }(중괄호)로 해당 메서드가 끝나게 되면 스택에서 자동으로 제거된다. 그래서 Value Type은 메모리 걱정을 안해도된다.

문제는 Reference Type에서 발생한다. 
Reference Type이 선언되면, 힙에 데이터가 저장되고, 스택에 그 데이터를 참조하는 주소값이 저장되는데
여기서 해당 Reference Type이 선언된 메서드가 종료하면 스택만 정리되기 때문에 힙에 있는 데이터는 그야말로 쓸모없는 쓰레기 상태가 되어버린다. 
이런 경우가 많아질 수 록 점점 쓰레기는 쌓여갈테고, 메모리 문제가 발생할텐데 이걸 정리해주는게 바로 Garbage Collector다.



GC는 이럴때 발생한다.
1. Generation 0, 1, 2중 하나라도 찼을 때
2. GC.Collect()가 직접 호출됐을 때
3. 운영체제가 메모리 부족이라고 판단했을 때

여기서 Generation 0, 1, 2 란?
GC를 효율적으로 관리하기위해 메모리 정리 기준을 3개로 나눈 것이라고 할 수 있겠다.
처음 힙메모리에 저장되는 애들은 Generation 0에 들어가고, 이 Generation 0이 모두 차면 GC가 실행되고 남은 것들은 1로 간다.  그리고 그렇게 Generation 1이 가득 차고 또 다시 GC가 실행됐을때 1인 것들이 사라지지 않고 남아있으면 2가 된다.

0이나 1이 모두 찼을 때는, 해당 Generation번호에만 GC가 실행된다. (0에서 GC가 실행되고 1로 쓰레기들이 넘어왔는데, 이게 1의 크기를 초과한다면 1에서도 GC가 연속적으로 발생한다.)
2가 모두 찼을때는 0, 1, 2에 대해 모두  GC를 실행(Full GC)한다.

0, 1, 2에 대한 크기는 각각 상황에 따라 동적으로 변한다고 하는데 0, 1, 2순으로 점점 커진다.

그리고 GC가 발동해서 힙의 메모리가 정리되었을때 메모리가 띄엄띄엄 비어있을 수 있는데 LOH에서는 이를 그대로 두지만 SOH에서는 압축해서 메모리 단편화를 방지해준다.



그럼 LOH(Large Objects Heap)란?
85KB이상 크기인 객체를 저장하는 곳이 따로 있어 따로 관리된다. SOH(Small Objects  Heap)은 85KB 미만으로 위에서 설명한 GC 구조로 실행된다.

그리고 당연하지만 unmanaged memory에 속하는건 GC에서 정리해주지 않는다. 이는 유의해서 메모리 해제를 잘 하면 좋겠다..