본문 바로가기
Computer Science/Operating System

가비지 컬렉션(Garbage Collection, GC) 알아보기

by ggyongi 2022. 4. 14.
반응형

GC란?

Java의 경우, 유효하지 않은 메모리인 가비지를 JVM의 가비지 컬렉터가 자동으로 메모리에서 해제시켜준다. 

 

GC 기본 동작 과정

1. Stop the world

가비지 컬렉션 실행을 위해 어플리케이션이 일시 정지가 되는 상태. GC를 수행하는 스레드를 제외한 모든 스레드는 동작을 멈춘다.

 

2. Mark and Sweep

사용되는 메모리와 사용되지 않는 메모리를 식별(Mark)하고 사용하지 않는 메모리를 힙으로부터 해제(Sweep)

 

Minor GC와 Major GC

힙영역을 물리적으로 Young 영역과 Old 영역으로 나눈다.

 

- Young 영역(Young Generation)
새롭게 생성된 객체가 할당되는 영역
대부분의 객체가 금방 Unreachable 상태가 되기 때문에, 많은 객체가 Young 영역에 생성되었다가 사라진다.
Young 영역에 대한 가비지 컬렉션을 Minor GC라고 부른다.

 

- Old 영역(Old Generation)
Young영역에서 Reachable 상태를 유지하여 살아남은 객체가 복사되는 영역
Young 영역보다 크게 할당되며, 영역의 크기가 큰 만큼 가비지는 적게 발생한다.
Old 영역에 대한 가비지 컬렉션을 Major GC 또는 Full GC라고 부른다.

 

- 카드 테이블 영역

Old 영역에서 Young 영역으로 참조가 일어날 수 있는 상황을 대비하여, 이 경우 카드 테이블에 그 정보를 표시해둠. 이로써 모든 Old 영역을 탐색하지 않아도 참조 여부를 알 수 있게 된다. 따라서 Young 영역에서 GC가 실행될 때 살아남아야 할 객체를 빠르게 식별할 수 있다.

 

Minor GC

Young - 1개의 Eden, 2개의 Survivor로 구성

Eden : 새로 생성된 객체가 할당되는 영역

Survivor : 최소 1번 이상 GC에서 생존한 객체가 존재하는 영역

 

1. Eden에 새로 생성된 객체 할당

2. Eden이 꽉 차면 Minor GC 실행, 사용하지 않는 객체를 메모리에서 해제하고 사용하는 객체는 Survivor로 이동

3. 위 과정이 반복되다 Survivor도 가득 차게 되면, Survivor의 살아남은 객체들을 다른 Survivor로 이동시킴

4. 이 과정을 반복하다 계속 살아남은 객체는 Old 영역으로 이동(promotion)

 

* 객체의 생존 횟수를 의미하는 age를 object header에 기록, Minor GC 때 age를 보고 promotion을 결정

* Survivor 2개 중 1개는 반드시 사용되어야 함. 두 영역에 모두 객체가 있거나 모두 객체가 없다면 그것은 비정상

* Hotspot JVM : Eden 영역에 객체를 빠르게 할당하기 위해 2가지 기술 사용

1. bump the pointer : 마지막으로 할당된 객체의 주소를 캐싱해둠, 이로 인해 객체를 위해 유효한 메모리를 탐색할 필요가 없어짐

2. TLABs(Thread Local Allocation Buffers) : 멀티스레드 환경에선 객체를 Eden에 할당할 때 lock을 걸어 동기화를 해줘야 함. TLABs는 각각 스레드마다 Eden 영역에 객체를 할당하기 위한 주소를 부여하여 동기화 작업없이 빠르게 메모리를 할당해주는 기술

 

Major GC

객체들이 계속 promotion되어 Old 영역의 메모리가 부족해지면 Major GC 발생.

Old 영역은 Young영역에 비해 크기도 크고 Young영역을 참조할 수도 있어서 일반적으로 Major GC는 Minor GC보다 10배이상의 시간이 소요됨(Minor GC는 보통 0.5~1초)

 

 

다양한 GC 알고리즘

Serial GC

young 영역 : mark sweep 그대로 실행

old 영역: mark sweep compact 실행. compact는 힙영역을 정리하기 위한 단계. 유효한 객체들이 연속되게 쌓이도록 앞부분부터 채움.

* 1개의 스레드만 사용하기 때문에 여러개 CPU 코어를 운영하는 서버에선 절대 쓰면 안됨

 

Parallel GC

기본적인 처리과정은 Serial GC와 동일.

다만 여러개 스레드 사용 -> parallel하게 GC를 수행하여 오버헤드 감소.

상당한 오버헤드를 줄였지만 여전히 application이 멈추는건 피할 수 없음 -> 새 알고리즘 고안

 

Parallel Old GC

old영역에서 mark sweep compact가 아닌 mark summary compaction 사용

 

CMS(Concurrent Mark Sweep) GC

여러개 스레드 이용 + Concurrent 하게 mark sweep을 수행.

application 지연 시간을 최소화하기 위해 고안. 프로세서의 자원을 공유하여 이용 가능 해야 함. CMS가 수행될 때는 자원이 GC를 위해서도 사용되므로 응답이 느려질 수 있지만 응답이 멈추지는 않게 됨.

다른 GC보다 많은 메모리, CPU가 필요하며 compaction을 사용하지 않는 건 단점. 장기적으로 운영되다 조각난 메모리가 많아 compaction이 수행되면 오히려 stop the world가 길어질 수 있음

 

G1(Garbage First) GC

CMS CG를 대체하기 위해 개발됨.

기존 GC 알고리즘이 young/old로 힙 영역을 물리적으로 나눈 것에 비해, G1 GC는 Eden 영역, Survivor를 사용하긴 하지만 물리적으로 메모리 공간을 나누지는 않음. 대신 지역(region) 개념을 도입.

 

Region

Heap 영역을 여러 지역으로 균등하게 나누고, 각 지역을 역할과 함께 논리적으로 구분(eden or survivor or old)하여 객체를 할당. 이때 기존 Eden, Survivor, Old 이외에 Humongous와 Available/Unused 2가지를 추가.

Humongous : 지역 크기의 50프로를 초과하는 객체를 저장하는 지역

Available/Unused : 사용되지 않는 지역을 의미

 

G1 GC의 핵심 : 힙영역을 동일 크기의 지역으로 나누고 가비지가 많은 지역에 대해 우선적으로 GC를 실행

 

G1 GC의 Minor Garbage

한 지역에 객체를 할당 -> 꽉차면 다른 지역에 할당하고 GC 실행.

G1 GC는 각 지역을 추적하고 있기 때문에 가비지가 많은 지역을 찾아가 mark and sweep을 수행.

Eden 지역에서 GC 수행되면 살아남은 객체를 다른 지역으로 이동시킴. available/unused로 이동되었다면 이 지역은 survivor 지역이 됨. Eden 지역은 available/unused가 됨

 

G1 GC의 Major Garbage

시스템이 운영되다 객체가 너무 많아 빠르게 진행될 수 없을 때 Major GC 실행.

기존 GC 알고리즘이 모든 힙 영역에 대해 GC가 수행되었던 것에 비해 G1 GC는 어느 지역에 가비지가 많은지 추적하고 있기 때문에 GC를 수행할 지역을 조합하여 이 지역들에서만 GC를 수행. 

작업은 Concurrent하게 수행되어 application 지연도 최소화됨.

* G1 GC는 물론 다른 GC에 비해 잦게 호출됨. 하지만 규모가 적고 Concurrent하게 수행되기 때문에 지연이 크지 않으며, 가비지가 많은 지역을 정리하므로 효율적임

 

=> G1 GC 방식이 현재 Java의 default GC (java9부터)

 

비전공자 네카라 신입 취업 노하우

시행착오 끝에 얻어낸 취업 노하우가 모두 담긴 전자책!

kmong.com

댓글