JVM의 GC동작, 몇 종류의 GC
JVM 의 GC 과정
- Garbage Collector가 Stack의 모든 변수를 스캔하면서 각각 어떤 객체를 참조하고 있는지 찾아서 마킹한다.
- Reachable Object가 참조하고 있는 객체로 찾아서 마킹한다.
- 마킹 되지 않은 객체를 Heap에서 제거한다.
위에서 1,2 - Mark, 3 - Sweep, 그래서 Mark & Sweep GC라고도 한다.
JVM의 Heap 영역은 Young 영역과 Old 영역으로 나누어진다.
Young 영역
Young 영역은 3개의 영역으로 나뉜다.
- Eden 영역
- Survivor 영역(2개)
- 새로 생성한 객체는 Eden영역에 위치한다.
- Eden 영역에 GC가 한번 발생한 후 살아남은 객체는 Survivor 영역(Survivor A)으로 이동한다.
- 그 이후로도 Eden 영역에서 GC가 발생하면 살아남은 객체는 Survivor A로 계속 이동하며 쌓인다.
- Survivor A영역이 가득 차게 되면 그 중 살아남은 객체를 다른 Survivor 영역(Survivor B)으로 이동한다. 그리고 Survivor A영역은 아무 데이터도 없는 상태가 된다.
- 1~4 과정을 반복한다.
- Survivor 영역이 가득 차서 다른 Survivor 영역으로 이동하면서 Age라고 하는 값들이 증가한다.
- 이 Age값들이 특정 값 이상이 되면 Promotion이라고 하는 것이 일어난다.
- 특정 Age 이상이 된 객체들은 Promotion으로 Old Generation 영역으로 이동하게 된다.
- 이 과정을 거쳐 Old Generation 영역이 가득찰 때 Major GC가 발생한다.
- 이 전체적인 과정을 반복하며 Garbage Collector가 메모리 관리를 한다.
** Survivor 영역 중 하나는 반드시 비어 있는 상태로 남아 있다.
그림으로 살펴보자
위와 같은 Minor GC과정을 반복하게 된다.
Promotion이 일어나고 Old Generation 영역이 채워지다가 가득차게 되면 아래 그림 처럼 Major GC가 발생한다.
몇 가지 GC의 종류
CMS GC (Concurrent Mark-Sweep)
Young 영역의 GC는 위의 설명과 같다.
Old 영역의 GC는 아래와 같다.
- Mark: 살아있는 객체를 찾는 단계(Stop-the-world)
- Concurrent Mark: 방금 살아있다고 확인한 객체에서 참조하고 있는 객체를 따라가면서 확인.(다른 쓰레드가 실행 중인 상태에서 동시 진행)
- Remark: Concurrent Mark 수행하면서 다른 쓰레드에 의해 새로 추가되거나 참조가 없어진 객체 확인(Stop-the-world)
- Concurrent Sweep: Garbage 정리(다른 쓰레드 실행 중)
CMS GC는 Stop-The-World 시간이 짧다는 장점이 있다.
단점은 메모리와 CPU를 더 많이 사용한다. Compaction 단계가 없다.
G1GC (Garbage First Garbage Collector)
전체 Heap을 체스판처럼 여러 영역으로 나누어 관리한다.
그림에서 하늘색 영역은 young generation이다. young generation이 가득차면 GC가 발생한다. 그리고 GC가 발생할 때 살아 있는 객체들은 복사된다.(이 과정에서 compact 효과도 있다.)
G1은 살아있는 객체를 새 영역에 복사할때만 애플리케이션을 멈춘다.
GC를 위해 Heap 전체를 찾지 않기 위해 G1은 영역의 참조를 관리할 목적으로 remember set을 만들어 사용한다.
궁금한 점
- JVM에서 GC가 일어날 때 한 트랜잭션이 끝났는지 어떻게 확인하고 Stop-The-World 하는가?
- GC가 돌 때 나머지 Thread들의 상태를 저장하고, GC가 돈다.
- 하지만 Transaction 관점에서 보면, 만약 DB에 insert하는 transaction 중간에 GC가 끼게된다면, timeout이 발생할 가능성은 생긴다.
- GC의 정책이 변경된다고 했을 때 예상치 못한 에러가 발생할 가능성이 있다.
댓글남기기