메모리 관리 기법 중 하나로, 동적으로 할당했던 메모리 영역 중 필요 없게 된 영역을 해제하는 기능이다.
여기서 동적으로 할당했던 메모리 영역은 프로그램 런타임에 사용되는 Heap 영역 메모리를 뜻하고, 필요 없게 된 영역은 어떤 변수도 가리키지 않게 된 영역을 뜻한다.
C/C++에서는 Heap 영역의 메모리를 사용하려면 직접 동적 메모리의 영역에서 할당 받고 해제하는 작업을 해줬어야 했다.
그러나 Java에서는 동적 메모리 영역을 GC가 알아서 수행해주므로 개발자 입장에서는 편하게 개발에 집중할 수 있다.
참고로 GC를 의도적으로 System.gc() 를 사용하여 호출할 수 있지만, 오버헤드가 굉장히 크므로 GC에게 메모리 해제를 믿고 맡기는 것을 추천한다.
GC는 스스로 메모리를 알쓸깔딱 하게 해제한다는데 그 과정부터 먼저 알아보자.
- 메모리가 사용되는지 안되는지를 구분한다.
위 사진에서는 참조되지 않고 있는 객체를 주황색으로 마킹한 것이다. 모든 객체를 하나씩 탐색하며 마킹하기 때문에 오랜 시간을 소모하게 된다.
- 1번에서 마킹을 했으니, 마킹한 객체 (참조되지 않고 있는 객체) 를 제거하고 메모리를 반환한다. => Memeory Allocator 는 반환되어 비어진 곳의 주소를 저장해뒀다가, 새로운 객체가 선언되면 이 곳에 할당되도록 한다.
- 문제 🤔
이렇게 하면 메모리가 단편화되어 비효율적으로 사용될지도 모른다 그렇기 때문에 흩어진 객체들의 영역을 한 곳으로 모으는 과정이 필요하다.
- 참조되는 객체들을 한 곳으로 집약
-> 남은 공간을 극대화함으로써 새로운 메모리 할당 시 훨씬 더 쉽고 빠르게 진행할 수 있다.
지금까지의 과정은 모든 객체를 탐색해가며 일일히 참조되지 않고 있는 객체를 마킹하고 메모리 해제하고 다시 메모리 압축하고 난리이다.도 아니다. 상당히 비효율적인 알고리즘이다.😥😥
대부분 객체는 금방 접근 불가능 상태가 되는데...
'신규'로 생성한 객체의 대부분은 머지않아 사용하지 않는 상태가 되고, '오래된 객체'에서 신규 객체로의 참조는 매우 적게 일어난다는 가정이
=> Weak Generational Hypothesis 이다.
- Y 축: 할당된 바이트의 수
- X 축은 바이트가 할당될 때의 시간이다.
=> 시간이 가면 갈 수록 적은 객체가 남게 된다.
이러한 가정하에 Young 영역과 Old 영역으로 메모리를 분할하여, 새롭게 생성되는 객체는 Young 영역에 보관하고, 점차 나이를 들게 한 다음 어느정도 나이를 먹은 객체는 Old 영역에 보관하는 알고리즘을 고안해냈다.
이것을 Generational Gabage Collection 이라고 한다.
.
.
새롭게 생성한 객체들은 대부분 이곳에 자리잡게 된다. Weak Generational Hypothesis 에 의거하면, 대부분 객체가 금방 접근 불가능 상태가 되기 때문에 매우 많은 객체가 이 영역에서 생성되었다가 사라지게 된다.
=> 해당 영역에서 객체가 메모리 해제되는 경우를 Minor GC 가 발생했다고 말한다.
금방 접근 불가능 상태가 된 녀석들과 달리, 꽤 오랫동안 메모리에 남아있던 객체들이 이 영역으로 복사된다.
그리고 최근 Minor GC 에서 S0 영역으로 이동된 객체들도 Age 가 증가하고, S1 영역으로 이동하게 된다. 모든 객체들이 S1 영역으로 이동하게 되면, Eden Space 와 S0 영역은 모두 클리어된다.
이제 우리는 각기 다른 Age 를 가진 객체들을 Survivor 영역에 가지게 된다.
- 하지만 이번 과정에선 Survivor 영역이 서로 스위치된다.
참조되는 객체들은 S0 으로 이동하고, 살아남은 객체들은 Age 가 증가한다.
=> 그리고Eden Space
와 S1 영역은 클리어 된다.
haero_kim님의 글을 참조하여 작성하였습니다.