Java

[Java] Garbage Collection 노트정리

leejunkim 2025. 5. 29. 22:10

Java의 Garbage Collection (GC)는 메모리 기법 중 하나로, 필요하지 않은 메모리를 치워두는 프로세스이다.

이 불필요한 메모리를 치워두지 않으면 memory leak, dangling pointer, 성능 저하 등 다양한 문제를일으킬 수 있기 때문에 java가 가지고 있는 중요한 기능 중 하나이다. JVM (Java Virtual Machine)이 이 기능을 담당한다.

 

먼저 java의 프로세스를 알아보려면

1. java는 메모리 (힙)에 오브젝트들을 만든다

2. 그 중 오브젝트(들)의 참조가 끊어질 때 (null이 되거나 참조가 바뀐다) 힙에 남아있는 데이터는 가비지가 된다 (GC에 정리 대상이 된다)

3. 이 가비지들은 GC에 의해 제거가 되고 메모리는 비게 된다

 

예시:

Character character = new Character();
character.setName("Kirby");
character = null;             // 참조 해제를 했으니, 이제 GC 대상

character = new Character();
character.setName("Yoshi");

character = new Character("Mario"); // 이전 인스턴스는 GC 대상

 

즉, Heap 영역의 객체 중 Stack에서 도달 불가능한 (unreachable) 객체들은 가비지 컬렉션의 대상이 된다.

 

특징

GC는 좀 신기한 특징들이 있다.

 

1. 내가 직접 실행을 안해도 된다

- 내가 직접 코드 안에 GC 실행해줘~라고 말하지 않아도 JVM이 알아서 직접 해주는 것이 큰 특징이다.

- 정말 내가 직접 실행하고 싶다면 System.gc()를 써서 요청이 가능하지만, 보장되지는 않는다.

- 참고로 C/C++와 같은 언어들은 개발자가 수동으로 메모리를 제거해야 하지만 자바는 그럴 필요가 없다는 뜻이다.

 

2. 언제 실행될지 예측할 수 없다

- 정해진 주기 없이, JVM이 판단하여 실행이 된다. (메모리 부족, 시스템 idle, 객체 수 급종 등 조건에 따라 동작함)

 

주요 동작 방식 - Mark and Sweep

GC가 동작하는 아주 기초적인 청소 과정이라고 보면 된다.

 

1. Marking (식별)

- 아직 참조되고 있는 오브젝트들을 식별하고 표시(mark)한다. 실행 스레드(roots)로부터 시작해서, 각 각체가 다른 객체를 참조하는지 여부를 파악한다. 거미줄처럼 생각하면 쉬울 것이다 (연결된 객체를 따라가보는 것)

- 이때 mark되지 않은 오브젝트들은 GC 대상이 된다.

2. Sweeping (제거)

- Marking phase 이후, GC는 힙을 돌아다니며 mark되지 않는 오브젝트들을 제거한다.

- 그냥 청소부라고 생각하면 쉽다. 마킹 단계에서 버려진 객체들이 차치했던 메모리 공간을 이때 회수한다. 

- 이때 회수된 메모리 공간은 앞으로 새로운 객체들이 할당될 수 있도록 준비가 된다. 

 

[Stop The World]

GC는 위의 mark & sweep과 같은 단계를 거쳐 메모리를 관리하는데, 이 과정에서 Stop-the-World가 발생할 수 있다.

- Stop-The-World(STW)는 GC가 실행되는 동안 어플리케이션 thread가 일시적으로 중단되는 현상을 의미한다.

- 이때 GC를 제외한 모든 thread는 작업은 멈춰지고, GC가 작업을 완료한 이후 작업은 다시 시작된다.

- 보통 GC의 성능 개선을 위해 튜닝을 한다고 하면 이 Stop The World의 시간을 줄이는 작업을 의미한다.

 

GC의 세대별 (Generational) 구조

영 세대 (Young Generation)

- 여기는 새로운 객체가 생성되는 공간이다. 

- 대부분 금방 사라지므로 GC가 자주 여기서 발생한다 

- 세부적으로 Eden, Survivor 영역으로 나뉜다. 새로 생성한 대부분의 객체는 Eden 영역에 위치한다. Eden 영역에서 GC가 한번 발생한 후 살아남은 객체는 Survivor 영역 중 하나로 이동하고, 하나의 Survivor 영역이 가득 차게 되면 그 중에서 살아남은 객체는 다른 Survivor 영역으로 이동한다.

- 즉, Survivor 영역은 최소 1번의 GC 이상 살아남은 객체가 존재하는 영역이다.

- 이 과정을 반복하다가 계속해서 살아남는 객체는 Old generation으로 넘어간다.

 

여기서 Eden Space가 가득 차면, Minor GC가 트리거되고, Eden 영역에 존재하는 객체는 (사용중인) Survivor 영역으로 옮겨고 사용되지 않는 메모리는 해제된다.

올드 세대 (Old Generation)

- Young generation에서 오래 살아남은 객체는 여기로 승격이 된다.

- Young 영역보다 크게 할당이 된다

- Young generation와 달리 여기 객체는 오랫동안 계속 있으므로 GC 발생 빈도가 낮다.

- 기본적으로 데이터가 가득 차면 GC를 실행한

 

여기서 객체들이 계속 Promotion되어 Old 영역의 메모리가 부족해지면 Major GC가 트리거 된다.

Old 영역은 Young 영역보다 크고 Young영역을 참조 할 수 있다.

 

다양한 GC 알고리즘

GC 종류 설명
Serial GC 단일 스레드, 소규모 애플리케이션에 적합
Parallel GC 멀티스레드 기반, Throughput 우선
CMS GC 애플리케이션 정지 최소화, Mark/Sweep 병렬 수행
G1 GC Java 11 이상에서 기본, Young/Old를 세분화하여 병렬 처리 및 예측 가능

 

출저/자료

- https://velog.io/@limsubin/GC-stop-the-world-%EB%9E%80

- https://mangkyu.tistory.com/118