2021
04.13

가비지 컬렉션(GC)

GC는 메모리 관리 기법 중 하나이다.

 

C와 C++로 개발할 때에는 객체를 선언하기 위해 메모리를 직접 할당하고,

사용이 끝나면 메모리를 해제해야 한다. (Unmanaged 언어)

 

하지만 C#과 Java에서는 가비지 컬렉터(GC)가 자동으로 메모리를 관리해 준다. (Managed 언어)

참고하면 좋은 글 : 닷넷 가비지 컬렉션 다시 보기 - Part I
http://www.simpleisbest.net/post/2011/04/01/Review-NET-Garbage-Collection.aspx

 

GC의 동작 방식

Mark and Sweep 알고리즘

1. 최상위 레퍼런스를 위한 GC Root가 존재한다. (여러개인듯)

2. 이 GC Root에서부터 참조를 타고 가면서 방문한 레퍼런스들에 Mark를 한다.

3. Mark가 끝나면 Mark 되지 않은 메모리들을 삭제(Sweep)하고, 메모리들의 위치를 재조정한다.

 

장점

 - 자동으로 메모리가 관리되기 때문에(Memory managed 언어) 프로그래머가 관리할 필요가 없다.

 - 메모리 누수의 위험이 적다. (동적 메모리를 선언하고 까먹고 해제 안 하는 위험이 없다.)

 - 이중해제 문제에서 자유롭다. (이미 해제된 메모리를 다시 해제하는 오류)

 

단점

 - 해제할 메모리를 조사하는데 비용이 든다.

 - 할당된 메모리가 해제되는 시점을 알 수 없다.

 - 실시간 시스템에서 프로그램 동작 중 GC가 원하지 않는 순간 발생하면 프로그램 동작에 문제가 생길 수 있다. 

 

 

 

유니티 클라이언트는 주의!
C#과 Unity의 가비지 컬렉션방법이 다르다...!

 

 

C# .Net환경의 가비지 콜렉션 : 세대별 GC

C#의. Net환경에서는 GC를 최적화 화기 위해 세대별 GC 기법이 사용된다.

 

3가지 세대(0세대, 1세대, 2세대)로 구분되어 최초 GC를 실행한 뒤, 살아남은 객체는 1세대로 옮겨진다.

이후 새롭게 할당된 메모리들에 대해서만 레퍼런스를 검사하고 GC를 수행하다가 0세대가 용량 한계가 되면,

1세대에 대해서도 레퍼런스 검사를 하고 살아남은 1세대는 2세대로 옮긴다.

 

메모리에 남아있었던 객체의 메모리들은 2세대에 계속 남아있게 되며,

즉 모든 메모리의 레퍼런스를 검사하는 것보다는 없어질 가능성이 높은 메모리들에 대해서만 먼저 검사를 하는 것이다.

 

 

Unity의 가비지 콜렉션 : Boehm-Demers-Weiser

유니티는 C#과는 다른 가비지 콜렉션 방식을 사용한다.

기본적으로 Mark and Sweep인 것은 같지만 그 이후에 세대구분이나 메모리 위치이동 등이 없는 듯.

 

중요한 건 가비지가 가득 차면 스레드를 멈추고,

가비지 정리를 한 다음 다시 프로그램을 이어 나가는 방식을 사용한다. 

 

때문에 Unity 2019 이전 버전에서의 유니티 게임들은  가비지 콜렉션이 발생하는 순간 급격한프레임드랍이 발생했다.

2019 버전에 추가된 점진적 GC는 여러 프레임에 걸쳐서 콜렉션을 수행하기 때문에 프레임 드랍이 눈에 띄지 않는다.

(수직동기화가 켜져 있다면, 수직동기를 위해 CPU가 쉬는 순간에 콜렉션을 자동으로 수행한다) 

 

 

 

COMMENT