Garbage Collection(GC)은 메모리 관리 기법 중 하나로, 프로그램이 동적으로 할당했던 메모리 영역 중에서 필요없게 된 영역을 해제하는 기능으로, 1959년 존 매카시라는 사람이 개발하였다.
프로그램을 개발하다 보면 유효하지 않은 메모리인 가비지(Garbage)가 발생한다. c언어에서는 free()라는 함수로 직접 메모리를 해제해주지만 자바나 코틀린에서는 이럴 필요가 없다. JVM 안에 있는 가비지 콜렉터가 불필요한 메모리를 알아서 정리해주기 때문이다.
(System.gc()라는 메소드를 명시적으로 호출할 수는 있지만 시스템 성능에 큰 영향을 주므로 절대 호출하지 않는것이 좋다고 한다.)
GC의 동작 방식은 2가지의 공통 단계를 따른다.
Stop The World 는 가비지 컬렉션을 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 작업이다.
이때는 GC를 실행하는 쓰레드를 제외한 모든 쓰레드의 작업이 중단되며 GC가 완료되면 재개된다.
이 시간을 STW라고 하며 GC 성능개선을 하기 위해 보통 이 STW를 줄이려고 한다.
Mark : 사용되는 메모리와 사용되지 않는 메모리를 식별하는 작업
Sweep : 마크 단계에서 사용되지 않음으로 식별된 메모리를 해제하는 작업
Heap 영역은 처음 설계될 때, 2가지를 전제로 설계되었다.
→ 객체는 대부분 일회성이며, 메모리에 오랫동안 남아있는 경우는 드물다.
그래서 객체의 생존 기간에 따라서 물리적인 Heap 영역을 나누었는데, Young, Old 2가지 영역이 설계되었다.
Young Generation
Old Generation
2-1)Eden 영역에서 사용되지 않는 객체의 메모리가 해제된다.
2-2)Eden 영역에서 살아남은 객체는 1개의 Survivor 영역으로 이동된다.
객체의 생존 횟수를 카운트하기 위해 Minor GC에서 객체가 살아남은 횟수를 의미하는 age를 Object Header에 기록한다. 그리고 Minor GC 때 Object Header에 기록된 age를 보고 Promotion 여부를 결정한다.
또한 Survivor 영역 중 1개는 반드시 사용이 되어야 한다. 만약 두 Survivor 영역에 모두 데이터가 존재하거나, 모두 사용량이 0이라면 현재 시스템이 정상적인 상황이 아님을 파악할 수 있다.
Young 영역에서 오래 살아남은 객체는 Old 영역으로 Promotion됨을 확인할 수 있었다. 그리고 Major GC는 객체들이 계속 Promotion되어 Old 영역의 메모리가 부족해지면 발생하게 된다. Young 영역은 일반적으로 Old 영역보다 크키가 작기 때문에 GC가 보통 0.5초에서 1초 사이에 끝난다. 그렇기 때문에 Minor GC는 애플리케이션에 크게 영향을 주지 않는다. 하지만 Old 영역은 Young 영역보다 크며 Young 영역을 참조할 수도 있다. 그렇기 때문에 Major GC는 일반적으로 Minor GC보다 시간이 오래걸리며, 10배 이상의 시간을 사용한다.
Java 8 이전에는 PermGen (Permanent Generation)이 존재하였음. 클래스나 메소드의 metadata를 저장하는 공간으로, old 영역에서 살아남은 객체가 저장되는 곳( Major GC가 일어남) 하지만, JAVA8 이후에는 Metaspace가 PermGen의 공간을 대체하게 되었다.