목차
1. CLR의 GC가 메모리를 할당하는 방식
2. GC가 발생했을 때 메모리 해제하는 방식
3. GC Collection, Finalizer와 GC의 관계
메모리 관리 기법중의 하나로 CLR에서 GC는 자동으로 어플리케이션의 메모리 할당 및 해제를 관리합니다. 더 이상 필요하지 않은 메모리 공간을 자동으로 해제하여 재할당을 가능하게 해준다.
.NET Framework의 VM 요소로 우리가 작성한 소스코드를 OS위에 있는 .NET Framework에서 작동하게 해주는 것 (GC는 CLR의 구성요소)
선형 메모리 할당 방식으로 다음 메모리 할당을 위한 포인터만을 유지하는 것으로 객체에 대한 메모리 할당이 이루어지면 단순히 포인터 값을 할당할 크기 만큼 증가시키고 할당할 메모리 값을 0으로 초기화 시켜 종료한다.
이런 방식을 통해서 메모리 조각 방식이 발생하지 않게 된다.
특정 조건이 되면(힙의 사용 가능 영역의 임계치에 다른다 등) 현재 수행중인 쓰레드들을 모두 중단시키고 GC 쓰레드를 활성화한다.
GC 쓰레드는 현재 사용중인 객체외에 사용하지 않는 객체들을 모두 힙 상에서 재배치하여 메모리 할당 포인터를 감소시킨다. 이러한 과정을 메모리 컴팩션이라고 한다.
동적으로 시스템을 구성하는 기억장소에서 여러곳에 흩어져 있는 가용 공간을 하나의 연속된 공간으로 만드는 작업. 기억장소의 할당과 반납과정에서 일어난 단편화 현상을 제거한다.
현재 객체가 사용중인지 알 수 있는 방법은 GC 쓰레드는 객체 참조 그래프를 생성한다.
루트 참조 그래프를 만든다.
루프 참조 그래프엔 아래와 같은 항목들이 포함된다.
- 현재 실행중인 쓰레드 내의 수행중인 메서드의 로컬 변수
- CPU 레지스터 변수의 참조
- 현재 사용중인 각 타입(Class)의 static field
- 전역 변수
루트 참조를 출발점으로 하여 각 루트 참조가 참조하는 객체, 그리고 다시 그 객체가 참조하는 다른 객체들을 연쇄적으로 참조 그래프에 추가한다.
이렇게 하면 현재 실행중인 객체가 무엇인지 알 수 있다.
그림으로 표현해보면 아래와 같다.
객체 참조가 되지 않는 B와 D 객체가 제거 될 것이라고 추측해볼 수 있다.
메모리 재할당 후 각 객체들의 참조 값이 변경된다. 이때 GC는 참조 그래프를 생성하면서 모든 객체의 정보를 가지고 있기 때문에 빠르게 작업을 수행한다.
GC의 성능 향상 및 효율을 높이기 위한 대표적인 최적화 방법중 하나이다.
관리되는 힙(객체가 있는 힙의 공간이라고 이해하자) 상의 객체를 생존 시간에 따라서 세대로 구분하여 GC를 수행하는 방법이다.
최근에 생성 된 객체는 0세대, 1회의 GC를 거쳐 살아남은 객체는 1세대, 2회 이상의 GC 동안 살아남은 객체는 2세대가 되는 방식이다.
GC는 0세대에 대하여 집중적으로 GC를 수행한다. 이렇게 하는 근거는 다음과 같다.
(사실 이부분의 완벽한 출처는 어디서 찾아야할 지 ... 논문일까..? 전공책일까 찾아봐라 ^^..)
- 최근 생성된 객체일 수록 생명주기가 짧다
- 오래된 객체일 수록 생명주기가 길다
- 최근에 생성된 객체들 끼리는 서로 연관성이 높고 비슷한 시점에서 자주 액세스 된다.
- 일부분의 힙을 가비지 컬렉션 하는 것은 전체를 가비지 컬렉션 하는 것 보다 빠르다.
GC가 실행될 땐 모든 쓰레드를 중지 후 GC가 실행되기 때문에 FULL GC를 수행할 땐 얼마나 객체가 많겠습니까 FULL GC의 오버헤드가 커지고 그래서 프로그램 중지 시간이 늘어나게 됩니다. 그래서 GC가 효율적으로 동작할 수 있도록 해주는게 중요하다.
http://www.simpleisbest.net/post/2011/04/01/Review-NET-Garbage-Collection.aspx
https://helloit.tistory.com/40
https://zagara.tistory.com/23