동적으로 할당한 메모리 영역 중 사용하지 않는 영역을 탐지해 해제하는 기능
Stack: 정적으로 할당한 메모리 영역
Heap: 동적으로 할당한 메모리 영역
즉, JVM의 Heap 영역에서 사용하지 않는 객체를 삭제하는 프로세스를 말한다.
C언어를 이용하면 free()라는 함수를 통해 직접 메모리를 해제해주어야 하지만 Java나 Kotlin을 이용해 개발하다 보면 개발자가 메모리를 직접 해제해주는 일이 없다. JVM의 Garbage Collector가 불필요한 메모리를 알아서 정리해준다.
Garbage Collector가 Stack의 모든 변수를 스캔하면서 각각 어떤 객체를 참조하고 있는지 찾아서 마킹한다.
Reachable Object가 참조하고 있는 객체도 찾아서 마킹한다.
마킹되지 않은 객체(Unreachable한 객체)를 Heap에서 제거한다.
1, 2의 과정을 Mark, 3의 과정을 Sweep이라고 하는데 이 과정, 즉 Garbage Collector 과정을 Mark and Sweep이라고 할 수 있으며 Reachable한 객체와 Unreachable한 객체를 식별하는 과정이라고 이해할 수 있다.
💡 참조되고 있는 객체들을 Reachable하다고 표현하고, 참조되고 있지 않은 객체들을 Unreachable하다고 표현함
Heap을 살펴보자
💡 Survival 영역의 규칙 - Survival 0에 객체가 있으면 Survival 1을 비워둬야 하고, Survival 1에 객체가 있으면 Survival 0을 비워둬야 함
GC설계자들은 두 가지 가설을 전제로 하여 GC를 만듦.
Most allocated objects are not referenced(considred live) for long, that is, they die young.
대부분의 객체는 금방 접근 불가능한 상태(unreachable)가 된다. 즉, 금방 garbage가 된다.
Few references from older to younger objects exist.
오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.
좀 어렵게 들릴 수 있는데 정리하자면 객체는 대부분 일회성인 경우가 많고 오래 머무르는 객체는 거의 없다는 이야기이다. 이런 특성을 반영해 자주 발생하는 Minor GC, 드물게 발생하는 Major GC 두 부분으로 나누어졌다.
수동으로 관리해야 하는 C언어와 달리 Java의 경우 JVM의 Garbage Collector가 불필요한 메모리를 알아서 정리해주기 때문에 편리하다.
장점
개발자의 실수로 인한 메모리 누수 예방 가능
해제된 메모리에 접근하는 오류 예방
해제된 메모리를 또 해제하는 이중 해제 예방
단점
오버헤드 발생
개발자는 GC가 언제 메모리를 해제하는 지 알 수 없음
JVM에서 GC가 진행되면 다른 동작이 멈추는 'Stop the World'가 발생하고 오버헤드가 발생하는데, GC가 자주 발생하게 되면 소프트웨어 기능 저하의 주요 원인이 될 수 있으므로 주의하여 사용해야 한다.