GC란 Garbage Collection의 약자다.
한마디로 정리하면, 쓰레기 객체 정리자
이다.
Java Runtime시 Heap 영역에 저장되는 객체들은 따로 정리하지 않으면 계속해서 메모리에 쌓이게되어 OutOfMemmory Exception이 발생하여 WAS 같은 경우 WAS가 다운될 수가 있다.
이를 방지하기 위하여 JVM에서는 주기적으로 사용하지 않는 객체를 수집하여 정리하는 게 GC의 역할이다.
개발자들은 이 GC가 어떤 주기로 돌아가는지는 모른다.
GC의 수거 대상은 GC Roots로부터 참조를 탐색했을 때, Unreachable한 Object들이다.
다음 순서로 GC가 동작이 된다.
1) Marking
- GC Root로 부터 모든 변수를 스캔하면서 각각 어떤 객체를 참조하고 있는지 찾아서 마킹한다.
2) Sweep
- Unreachable한 객체들을 Heap에서 제거한다.
3) Compact (optional)
- Sweep 후에 분산된 객체들을 Heap의 시작 주소로 모아 메모리가 할당된 부분과 그렇지 않은 부분으로 나눈다.
Eden영역부터 Servior영역까지를 Young 영역이라고 부른다.
GC가 인식하는 힙영역을 크게 Young
, Old
, Perm
영역으로 나눌 수 있다.
이중 Perm(Permanent)
영역은 거의 사용하지 않는 영역으로서 클래스와 자바 언어 레벨에서 사용되지 않느다.
이미지 출처 : https://mirinae312.github.io/develop/2018/06/04/jvm_gc.html
그러니 우리가 고려해야 할 자바의 메모리 영역은 총 4개의 영역으로 나뉜다. ( Young (1. Eden, 2. Survivor0 1, 3. Survivor1 2), Old (4. 메모리) )
GC가 처리하는 과정을 간단하게 정리하면 이렇다.
1) 객체가 생성되어 Eden 영역에 올라간다.
2) Eden 영역이 꽉 차면 Survivor0 영역으로 넘어간다. 단 Survivor 영역들 중 하나는 반드시 비어있어야 한다.
3) 이 과정에서 오랫동안 살아남은 객체는 Old 영역으로 이동한다.
처음 생성된 객체는 Eden 영역에 할당된다. 이후 Eden영역이 꽉 찬다면 할당이 해제되지 않은 객체를 Servior 영역으로 이동시킨다.
Eden 영역이 꽉차면 Minor GC
가 발생된다. Mark 과정에서 살아남은 객체들은 Survivor0 영역으로 복사하고, Eden 영역에 있는 데이터들을 삭제한다.
Survivor 영역에 있는 객체는 올라가있는 Survivor 영역이 꽉 찰 때 다시 GC 심사(Minor GC
)를 받는다. 즉, Eden영역과 Survivor0 영역을 모두 mark하고 살아남은 객체들은 Survivor1 영역으로 복사하고, Eden 영역과, Survivor0 영역의 데이터를 삭제한다. 복사가 될 때는 해당 객체의 Age값이 증가된다.
단, 여기서 Survivor 영역을 거치지 않고 바로 Old 영역으로 이동하는 경우가 있다. 바로 객체의 크기가 Survivor 영역의 크기보다 큰 경우다.
특정 age에 도달한 객체들은 Old generation 영역으로 옮겨진다. Young generation에서 Old generation으로 옮겨지는 현상을 promotion 이라한다.
Old 영역에도 데이터가 가득차면 Major GC
가 발생한다.
GC는 크게 Major GC
와 Minor GC
로 나눌 수 있다.
그 다음 Full GC
로도 나눌 수 있다.
Major GC
: Old, Perm 영역에서 발생하는 GCMinor GC
: Young(Eden, Survivor) 영역에서 발생하는 GCFull GC
: 메모리 전체를 대상으로 하는 GC이 두가지 GC가 어떻게 상호 작용하느냐에 따라서 GC 방식에 차이가 나며, 성능에도 영향을 줄 수 있다. GC가 발생하거나 객체가 각 영역에서 다른 영역으로 이동할 때 애플리케이션 병목현상이 발생하면서 성능에 영향을 끼치게 된다.
stop-the-world
: GC를 실행하는 쓰레드 외의 모든 쓰레드가 작업을 중단하는 것그래서 핫 스팟(Hot Spot) JVM에서는 스레드 로컬 할당 버퍼(TLABs: Thread-Local Allocation Buffers)
라는 것을 사용한다. 이를 통해 각 스레드별 메모리 버퍼를 사용하면 다른 스레드에 영향을 주지 않는 메모리 할당 작업이 가능해진다.
바둑판의 각 영역에 객체를 할당
하고 GC를 실행