프로그래밍 / C++ / 언리얼

카테고리 없음

[C#] 가비지 컬렉션(GC)

아트성 2022. 9. 8. 16:35

가비지 컬렉션 (GC)   

 

메모리를 자동으로 관리하는 기술이다. 

C++은 메모리를 프로그래머가 관리한다. 즉, 동적 할당된 메모리를 전부 사용했다면 시스템에 돌려줘야 한다는것이다.

이 과정에서 여러가지 실수가 많이 발생하는 데 아래와 같다.

 

 

메모리 누수(Memory Leak) 의 위험

메모리를 사용이 끝나고, 해제하지 않은 상태를 의미한다.

 

이중 해제(Double Free) 의 위험

이미 해제가 된 메모리를 또 해제하는 것이다.

 

섣부른 해제(Premature Free) 의 위험

아직 사용이 끝나지 않았음에도 해제하는것이다.

 

 

이런 불편함을 해결하기 위해서 수 많은 프로그래머들이 고민을 했고, 그러한 과정들을 거쳐서 자동메모리관리 기술(Automatic Memory Management) 즉,  가비지 컬렉션이 등장하게되었다.

 

 

 

 

 

동작 원리   

 

메모리의 재사용

가비지 컬렉션은 가비지 컬렉터가 더 이상 사용하지 않는 메모리를 재사용함.

 

 

객체의 사용여부 판단

어떤 객체가 사용되고, 사용되지 않는지 판별할 수 있는 알고리즘은 없다. 따라서 아래와 같은 방법으로 객체의 사용여부를 가정한다.

 

 

     1. 추적 가비지 컬렉션

 

      - 도달 가능성으로 생존을 가정.
      - 루트를 사용하여 해당 메모리까지 도달하지 못하면 가비지로 가정함.

 

 

   2. 참조 카운팅

     - 해당 메모리에 참조하는 것이 없을 때 가비지로 가정.

     - 순환 참조

           * 서로 다른 두 메모리가 서로를 참조하는 것.

           * 이를 방지하기 위해 약한 참조라는 개념 사용

           * 가비지 판단 기준인 참조 횟수에는 영향을 주지 않고 참조함

 

 

세대   

매니지드 힙

가비지 컬렉터가 관리하는 메모리이며 0세대, 1세대, 2세대 총 3개 세대로 나눠 관리한다. (세대를 나눈 이유는 메모리를 재사용하기 용이하기 때문이다.) 매니지드 힙의 특징으로는 여러 개의 포인터가 있으며 이를 이용해 세대를 구별한다. 또한 매니지드 힙에는 각 세대의 시작을 가리키는 포인터가 있다.

 

힙 관리의 장점

- 가비지 컬렉션이 일어날 때 파편화를 방지하기 위해 메모리를 압축하는 데, 힙 전체를 대상으로 하기보다 일부분에서만 수행 하는 게 더 빠르다.

 

- 최근에 생성 된 객체일 수록 수명이 짧고 오래 된 객체일 수록 수명이 길어 재사용할 메모리를 빠르게 분류할 수 있다.

 

- 메모리 할당은 0세대에서만 일어나는데 최근에 만들어진 객체끼리 서로 연관되는 경향이 있어 캐싱 측면에서 좋다.

 

 

 

메모리 할당   

C#에서 모든 참조 타입의 객체는 매니지드 힙의 0세대에 한다. 매니지드 힙은 메모리를 미리 시스템으로부터 할당 받아 놓아서 빠른 할당, 빠른 접근이 가능해진다. 그러나 85KB 이상 크기의 규모가 나가는 객체는 2세대 메모리에 할당된다.

 

 

메모리 해제   

세대별 가비지 컬렉션은 추적 방식을 사용한다. 루트에는 스택루트, CPU 레지스터, 정적 필드 등이있는데, 

수집 시기는 가비지 컬렉터가 자동으로 결정하고 컬렉션을 수행한다.

 

매니지드 힙을 검사해 가비를 찾으면 접근할 수 있는 객체를 압축해 가비지의 공간을 덮는다.

가비지 컬렉션은 0세대에서 일어남. 이후 가비지가 아닌 메모리는 윗세대로 승격되고, 0세대에서 메모리 공간이 부족하면 1, 2세대 순으로 가비지 컬렉션을 수행한다.

 

 

주의 사항   

가비지 컬렉션은 성능과 직결되며, 결코 자원을 적게 사용하는 연산이 아님. 도한 멀티스레드 환경인 경우 가비지 컬렉션이 수행되는 동안 다른 스레드가 중단되는 현상도 발생한다. 이런점을 고려해 아래 몇가지 주의사항들이 있다.

 

 

 

빈번한 할당을 조심

가비지 컬렉션은 객체를 할당할 충분한 공간이 없을 때 일어나는데, 특히 0세대가 가득 찼을 때 객체를 빈번하게 생성할 경우 0세대가 가득차서 가비지 컬렉션이 일어날 수 있다.

 

큰 객체 할당은 가급적 피해야함.

85KB가 넘으면 LOH에 할당되는데 LOH는 메모리 압축이 일어나지 않아 내부 단편화가 발생한다.

 

복잡한 참조 관계를 피해야함.

가비지 컬렉션 후에 메모리 주소 관리를 어렵게헌다, 또한 오래된 세대에서 새로운 세대에 대한 메모리를 참조할 때 수집 방지를 위해 쓰기 장벽을 만드는데 이는 많은 성능을 필요로한다.

 

관리되지 않는 리소스도 염두 해야함.

대부분의 리소스는 관리되지만 파일 핸들, 윈도우 핸들, 네트워크 연결 등의 운영체제 리소스를 래핑하는 경우 제대로 정리가 되지 않는경우가 있으므로 관리안되는 항목이 있따는것을 항상 염두해두어야한다.

 

반응형