닷넷의 가바지 컬렉터가 작동하는 원리를 알아보자~ 메모리 할당, 메모리 관리, 메모리 해제로 크게 나누어
볼 수 있으며 메모리 할당은 일반적인 Heap과 마찬가지로 다음 할당할 포인터 위치를 가지는 포인팅을 하고
새 객체가 생성되면 그 객체의 크기를 조사하여 managed heap의 공간이 충분한지를 검사하게 된다.
만일 충분한 공간이 있다면 연속적으로 메모리 할당이 이루어지고 이러한 연속적인 메모리 할당을 통해
객체들끼리의 따른 접근속도가 빠른 이점을 가질 수 있는 것이다.( 비슷한 시기에 생성된 객체들은 인접한
공간에 할당되기 때문에 접근속도가 용이하다. )
할당과정을 간력히 적어보면
프로세스 초기화 -> 주소 공간 예약 및 포인팅 -> 객체생성 -> 새 객체의 메모리 용량 계산 -> 힙메모리 여유 공간 조사 -> 예약된 메모리 영역에 객체 할당 -> 다음 객체 포인터 이동
으로 요약된다.
메모리 관리를 위해서 가비지 컬렉터는 3가지의 세대로 분리하여 관리한다. 즉 매번 가비지 컬렉션 대상을 위해
모든 managed heap영역을 다 검사하지 않는다는 것이다. 실제로 모든 영역을 때마다 계속 하게되면 프로세스
구동에 있어서도 성능의 저하가 눈에 보이게 된다고 한다. 다시 돌아와서 CLR은 Heap영역을 0,1,2세대로 나누어서 관리한다고 했다. 객체가 제일처음 생성되면 0세대로 분류되고 다음 가비지컬렉션이 발생하여 쓰지 않는 메모리를 검사하는 과정에서 살아남은? 객체는 1세대로 올라가게 된다. 이렇게 하여 최대 2세대까지 올라갈 수 있게
되고 예로 main에서 쓰이는 객체경우 중간에 호출되는 메소드내의 객체보다는 오래 살 가능성이 크기 때문에
2세대까지 올라가는 경우가 많다고 생각하면 이해가 쉬울것이다.
결국 가비지 컬렉터는 할당하고자 하는 객체의 메모리 크기가 모자랄 경우 0세대를 검사하여 가비지를 골라내고
만일 이러한 한번의 과정을 통해서도 메모리의 부족할 경우 1세대에 대한 가비지 대상을 검사하게 된다. 이때
1세대를 검사할때는 그 밑의 세대인 0세대도 같이 수행하는데 이를 보면 결국 2세대까지 올라가서 검사를 한다는
것은 모든 managed heap영역을 검사한다는 말이 된다. 실제로 2세대까지 올라가서 검사하는 경우는 거의 없다고 한다.
0세대 가비지 수집 -> 메모리 부족 -> 1세대 가비지 수집(0세대 동반) -> 메모리 부족
-> 2세대 가비지 수집(1,0세대 동반)
그러면 가비지 수집은 어떻게 하는 것일까? 참조 경로에 대한 정보를 수집하는 것이다. 참조경로는 그럼 누가
될까? 참조경로는 첫번째 시작점으로 전역 객체나 정적 객체에 대한 참조가 루트가 된다. 또한 스택에 있는
지역변수, 매개변수의 객체 참조등도 루트가 될 수 있다. 이러한 참조를 이용하면 참조계수를 이용한 방법보다
안정적으로 사용할 수 있고 이렇게 참조정보를 수집한 그래프를 통해 참조 당하지 않는 객체를 가비지로 판단하는
것이다.
루트를 통해 참조 그래프를 생성하고 여기에 나타나는 않는 객체를 가비지가 된다. 이 객체에 대해서는 메모리 해제가 일어난다. 가비지 대상으로 표시된 영역에 대해 유효한 객체를 차례대로 재배치함으로써 덮어버리면서 연속적인 메모리 구조를 유지한다. 85KB이상의 큰 객체는 LOH( Large Object Heap )이라는 곳에 할당되고 이 영역은 재배치 하지 않는다. 너무 크기가 크기 때문에 재배치 자체가 메모리의 비효율을 가지고 오기 때문이다. 그 다음 살아남은 세대는 다음 세대로 올라가게 되고 최대 2세대까지 올라갈 수 있다고 했다. 가비지 컬렉션이 완료되면
다음 새 객체의 할당을 위해 빈 메모리의 시작주소를 새로 지정해 주게 됨으로써 모든 작업이 끝난다.
가비지 컬렉션 수행절차를 간략히 보자~
객체 그리프 생성 및 유효한 객체 추적 -> 가비지 객체 결정, 표시 -> 메모리 재배치( Memory Compaction ) -> 객체참조 값 조정 -> 유효 객체에 대한 세대 상승 -> 새로운 포인팅
ps. '사랑하지 않으면 떠나라'인가..라는 책을 보면 저자가 인도의 개발자들을 뽑을 때 면접질문이 C#코딩으로 가비지 켈렉션을 뻗게 하는 방법이 어떤 것이 일을까? 라는 질문을 많이 했었다고 한다. 그때 제대로 틀린말조차
하는 사람이 없었다고 한다. 이러한 내부에 대한 이해가 없이 프로그램을 개발하는 경우가 많은 이때 여러 생각을 하게 했던 대목이였다.ㅎㅎ 이때쯤 한번씩 생각해보기 바란다. " C#코딩으로 가비지 켈렉션을 뻗게 하는 방법이 어떤 것이 일을까?"
참조 : 마소2008.04