JVM Garbage Collection
Garbage Collection(GC) 은 JVM이 더 이상 사용되지 않는 객체(garbage) 를 자동으로 찾아 메모리에서 제거하는 기능이다.
Garbage Collection 실행 조건
GC는 메모리 사용 상황에 따라 JVM이 판단하여 실행. 주로 아래 같은 상황에서 트리거 됨.
- Eden 공간 부족: JVM 메모리 구조에서 Young Generation 영역에 객체를 할당할 공간 부족한 경우
- Survivor 공간 부족: 객체를 Survivor로 옮기려고 할 때 공간 부족한 경우
- Old Generation 공간 부족: Old 영역이 임계치에 도달하는 경우 (FULL GC 발생)
- OOM 임박: OOM이 발생할 가능성이 있는 경우
Garbage Collection 메모리 수거 방법
가비지 컬렉션(Garbage Collection)은 도달성 분석(Reachability analysis)을 개념을 이용하여 객체가 GC Root로부터 도달 가능한(reachable) 상태를 확인하며 객체가 참조 되고 있지 않다면 도달 불가능한(unreachable) 상태로 판단해 수거 한다.
new 키워드로 생성된 객체는 Heap에 저장되며 GC는 주로 Heap을 관리하며 Stack, Method Area에서는 Heap에서 생성된 객체의 주소만 참조하는 형식으로 구성된다.
Heap에 생성되어 있는 객체가 제거되거나 null 할당, 메소드 종료(참조 범위 벗어남) 등 이벤트시 GC Root에서 도달할 수 없다고 간주하며 메모리 수거 대상이 된다.
GC는 어떤 알고리즘을 사용하든 소위 "Stop-The-World(STW)"가 발생하는데, JVM이 애플리케이션을 일시 중지하고 GC 작업을 단독으로 수행한다.
STW (Stop the world)
- GC를 수행하기 위해서 어플리케이션 실행을 멈추는 것으로 GC 시작시 모든 Thread는 멈추게 된다.
애플리케이션이 객체를 계속 생성하고 수정한다면 무결성과 정확성을 보장할 수 없기 때문에 정지(STW)를 한다. - 알고리즘 별로 STW 발생 시점, 지속 시간은 차이가 있을 수 있다.
- 대개 GC 튜닝은 STW 시간을 줄이는 것을 목표로 한다.
Mark and Sweep
Mark and Sweep은 JVM뿐만 아니라 여러 런타임 환경에서 사용되는 가장 기본적인 Garbage Collection 알고리즘으로
도달할 수 없는(unreachable) 객체를 식별하고 제거하여 메모리를 회수 한다.
Mark and Sweep은 간단한 구현과 정확한 분석이 가능하지만 현대 GC에서 단독으로 사용 되지는 않으며 G1, ZGC 등의 기초 알고리즘으로 기반으로 되고 있다.
- Mark: GC Root에서 그래프 순회를 통해서 연결된 객체를 찾아내어 참조(reachalbe)하고 있는 객체들을 마킹한다.
- Sweep: 참조하고 있지 않는 객체(unmark, unreachable) 객체들은 Heap에서 제거한다.
약한 세대 가설, weak generational hypothesis
- 대부분의 객체들은 짧은 시간 동안만 살아 있고 금방 접근 불가능한 상태가 된다.
- 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.
Heap Memory Structure
Heap 메모리 구조는 약한 세대 가설에 최적화를 하여 아래처럼 세대 구조로 관리 된다.
- Young Generation: 새로 생성된 객체가 위치, 대부분의 객체는 여기서 생성 후 바로 수거(GC)
- 이 영역에서 객체가 사라질때 Minor GC가 발생한다고 말한다.
- Eden: 대부분의 객체가 여기서 생성
- Survivor Space: 살아남은 객체가 이동. S0, S1 두개중 반드시 하나는 비어 있어야 한다.
- Old Generation: 오래 살아남은 객체가 이동
- 대부분 Young 영역보다 크게 할당하며 GC는 적게 발생한다.
- 이 영역에서 객체가 사라질 때 Major GC(Full GC)가 발생한다고 말한다.
- Metaspace(구, Permanent Generation): 클래스 메타 정보로 Java8부터는 Heap 외부(native 영역)에 존재
Minor GC
Young Generation에서 발생하는 GC로 Old Generation에 비해 작기때문에 상대적으로 적은 시간이 소요된다.
1. 새로 생성된 객체는 Eden 영역에 위치
2. 객체가 계속 생성되어 Eden 영역이 꽉차게 되는 경우 Minor GC 실행
3. GC Root에서는 도달 가능한(Reachable) 객체를 탐색 시작하고 표시(Mark) 한다.
4. Eden 영역에서 살아남은 객체는 Survivor 영역으로 이동
5. Eden 영역에 도달할 수 없는(Unreachable) 객체들 메모리 수거(Sweep)
- Survivor 영역으로 이동된 객체들의 age 값이 1 증가
6. 시간이 지나서 Eden 영역에 생성된 객체들로 차게되면 다시 Minor GC가 실행되고 다시 3-5 과정을 수행한다.
Minor GC는 Eden 영역이 가득 찼을 때 발생하며, GC 중에는 STW가 일시적으로 발생한다. GC Root에서 Young Generation 내 도달 가능한 객체는 새 Survivor 영역 또는 Old Generation으로 복사된다.
Major GC (FULL GC)
Major GC는 Old Generation의 객체를 수거하는 GC 작업으로, 대부분의 경우 Stop-The-World(STW)를 동반하며
Perm/Metaspace까지 포함한 전체 Heap의 GC를 통칭하여 Full GC라고 부르기도 한다.
1. 객체의 age가 임계값(설정값)에 도달하게 되면 이 객체들은 Old Generation으로 승격(Promote)한다.
2. Old Generation 영역이 차게 되면 Major GC가 실행 된다.
Major GC 실행시 Old Generation 영역은 Young Generation에 비해 큰 공간으로 GC에서 더 많은 시간이 필요로 한다. 문제는 GC 수행을 위한 STW(Stop-The-World)으로 요청 처리가 중지되므로 서비스에 장애 원인이 될 수 있다.