Garbage Collection
JVM의 Garbage Collection에 대해서 알아봅니다.
Goal
- JVM의 실행엔진 안에 속해있는 GC에 대해서 알아봅니다.
- GC의 동작방식에 대해서 알아봅니다.
- GC의 알고리즘 종류에 대해서 알아봅니다.
What is GC
사용되지 않는 객체에 대한 메모리 할당을 자동으로 해제 시켜주는 기술을 이야기합니다.
- 기본적으로 Java Heap 영역의 메모리를 다룹니다.
How Working
가비지 컬렉션 과정 - Generational Algorithm
새롭게 생긴 객체는 금방 없어지고, 오래 버틴 객체는 오래 버틴다는것을 기반으로 가져갑니다.
java7
java8
- Heap은 Young영역과 Old영역 으로 메모리를 분할하고, 신규로 생성되는 객체는 Young 영역에 보관합니다.
- Young영역에서 객체가 사라질때를
Minor GC
, Old영역에서 객체가 사라질떄를Major GC
라고 부릅니다. - Eden space에 객체를 채우다가 가득차면
Minor GC
가 발생합니다
Young 영역
- Eden
- Survivor (2개)
- 처음 생성된 객체는 Eden 영역에 위치합니다. Eden 영역이 가득차면 Minor GC가 시작됩니다.
- 먼저 참조된 이력이 있는 객체들은 age를 높여 s0 에 이동을 시키고, 그렇지 않은 객체들은 제거됩니다.
- 또 다음 Minor GC가 일어나면, s0와 Eden에 있던 객체중 참조된 것은 s1으로 이동하고 나머지 공간인 s0과 Eden에 있는 객체들은 제거됩니다.
- s0와 s1는 번갈아가서 반복되기 때문에, s0이 생존공간이 되고 s1, Eden의 객체들이 삭제되는 경우도 있을 수 있습니다.
- 일정 age가 넘어간 객체들은 old 영역으로 이동하게 됩니다.
- 이때 age 기본값은 31입니다. 해당 Age를 기록하는데 사용되는 bit가 6bit이기 때문입니다.
이외의 GC 알고리즘 종류
Reference Counting Algorithm
객체가 참조되어지고 있는 Count가 몇개인지를 확인하고 GC에서 지울지를 결정합니다.
- 0개가 되는 객체들은 메모리해제의 대상이 됩니다.
Mark and Sweep Algorithm
Reference Counting
는 순환참조를 해결하지 못한다는 단점이 있습니다. 이를 개선하기 위해 나온 방법입니다.
Root Set
로부터 접근 가능한 객체를 전부 Marking 해둡니다. 중복 되지 않게 Flag같은것을 심어둡니다.- Marking되지 않은 객체들의 메모리를 제거합니다.
- 하지만 메모리 중간중간이 비어있는 단편화 현상이 발생합니다.
Mark and Sweep Compaction Algorithm
메모리 단편화 현상을 해결하기 위해 나온 방법입니다.
- sweep 이후 단편화가 발생한 공간을 이어 붙입니다.
- 과거 디스크 모음조각을 하던 시절을 연상하면 기억하기 쉽습니다.
- 하지만 해당 부분을 이어붙이는데 들어가는 오버헤드가 발생합니다.
Copying Algorithm
Heap을 Active영역과 InActive 로 나누어서 관리합니다.
Generational Algorithm
의 과거 형태입니다.- 이 알고리즘도 단편화문제를 해결하고자 나온 알고리즘입니다.
- Heap영역을 절반으로 나눈뒤, Active영역에만 메모리를 할당합니다.
- Active 영역이 다 차게되면, 살아남는 객체들은 InActive 영역으로 Copy합니다.
- 이후 Active 영역의 Object들을 삭제합니다.
- Active와 InActive의 위치를 서로 바꿉니다.
- 하지만 힙의 절반영역밖에 쓰지 못하는 단점과, Copy과정에 들어가는 오버헤드가 있습니다.
GC 종류
GC별 동작 방식을 정리한 내용은 글을 분리해서 작성할 예정입니다.
- Serial GCL (mark sweep compact)
- Parallel GC: java8 디폴트 (쓰레드 병렬처리)
- Parallel Old GCL: (Mark Summary Compact)
- CMS: (stop the world는 짧지만, 메모리 CPU 낭비가 심한 GC)
- G1GC: Java11 디폴트 (큰 메모리에 적합한 GC, 이전에는 Heap이 작았기 때문에 순차적으로 접근해도 큰문제가 없었음)
- 기존의 young old 영역의 heap 형태는 잊어야 합니다.
- 영역이 다차면 다른 영역에 객체를 할당하고 GC 진행
- Z1 GC: (Java11 부터 일부 도입)