
Oracle의 공식문서 HotSpot Virtual Machine Garbage Collection Tuning Guide을 참고했습니다.
📍 Introduction to Garbage-First (G1) Garbage Collector
📍 Enabling G1
📍 Basic Concepts
현재 대부분의 jvm에서 사용하는 Garbage-First (G1) Garbage Collector의 개념과 과정에 대해 알아보자.
Garbage-First(G1) 가비지 컬렉터는 다중 프로세서 환경과 대용량 메모리 시스템을 대상으로 설계되었다.
G1은 가비지 컬렉션(GC) 일시 중지 시간을 최대한 일정하게 유지하면서 높은 처리량을 제공하도록 설계되었으며, 최소한의 설정으로도 효율적으로 동작한다.
일시 중지 시간을 일정하게 유지한다는 뜻:
• 게임을 하다가 갑자기 3초 동안 멈춘다면? 🎮❌
• 웹사이트에서 버튼을 눌렀는데 5초 동안 반응이 없다면? 🖱️❌
➡️ 이런 긴 멈춤을 방지하고, 가능한 한 일정한 간격(예: 100ms 내외)으로 짧게 유지
높은 처리량을 제공한다는 뜻:
메모리를 관리하는 시간(GC 시간)보다 실제 작업을 수행하는 시간(처리량)이 더 중요
✅ 필요할 때만 메모리를 정리하고
✅ 멀티코어를 활용해서 여러 작업을 병렬로 처리하며
✅ CPU를 너무 많이 쓰지 않게 조절하면서
➡️ 애플리케이션이 최대한 빠르게 실행될 수 있도록 도와줌
➡️ 수십 GB 이상의 큰 메모리를 사용하는 앱에서도 잘 동작
➡️ 자주 사용되지 않는 부분부터 정리해서 속도를 최적화
➡️ 데이터를 정리할 때 조각난 메모리를 모아서 효율적으로 재사용
➡️ GC가 실행될 때 앱이 잠깐 멈추는데, G1은 그 시간을 수백 밀리초 이내로 짧게 유지해서 사용자 경험을 좋게 만듦
➡️ 다른 GC 방식과 달리, 앱이 실행되는 동안에도 일부 정리를 수행해서 갑자기 오래 멈추는 걸 방지
G1은 여러 개의 가비지 컬렉션 스레드를 사용하여 애플리케이션과 동시에 일부 작업을 수행한다.
따라서 이전의 처리량 중심 수집기(Throughput Collector)보다 GC 일시 중지 시간이 짧아지는 대신 애플리케이션의 전체 처리량은 다소 감소할 수 있다.
G1은 기본적으로 활성화되어 있으며, 명령줄에서 -XX:+UseG1GC 옵션을 사용하여 명시적으로 설정할 수도 있다.
G1은 세대별(Generational), 점진적(Incremental), 병렬(Parallel), 대부분 동시(Concurrent), 일시 정지(Stop-the-World), 이동식(Evacuating) 가비지 컬렉터이며, 일시 정지 시간 목표를 실시간으로 모니터링한다.
다른 GC와 마찬가지로 G1은 힙을 젊은 세대(Young Generation)와 노년 세대(Old Generation)로 나누고, 젊은 세대에서 주로 메모리를 회수하며 필요할 때 노년 세대도 정리한다.
👉 힙을 젊은 세대(Young Generation)와 노년 세대(Old Generation)로 나눠서 관리
👉 한 번에 모든 메모리를 정리하는 게 아니라, 조금씩 나눠서 정리
👉 여러 개의 GC 스레드를 동시에 사용해서 빠르게 정리
👉 애플리케이션이 실행되는 동안에도 일부 GC 작업을 병렬로 수행
👉 GC가 객체를 실제로 정리할 때는 애플리케이션을 잠깐 멈춰야 하지만(Stop-the-World, STW) 이 멈추는 시간이 최대한 짧아지도록 조정함
👉 메모리를 정리할 때, 살아있는 객체를 새로운 영역으로 이동시키고, 이전 메모리는 깨끗이 비워서 재사용 가능하도록 만듦
G1은 힙을 동일한 크기의 여러 개의 힙 영역(Heap Region)으로 나눈다.
각 힙 영역은 연속된 가상 메모리 공간으로 구성되며, 개별 영역이 메모리 할당 및 회수 단위로 사용된다.
각 영역은 다음과 같은 역할을 한다.
애플리케이션은 기본적으로 Eden 영역에서 객체를 할당하지만, 크기가 매우 큰 객체는 바로 Old Generation으로 할당될 수 있다.
G1의 GC 주기는 크게 두 가지 단계로 나뉜다.
1. 젊은 세대만 처리하는 단계 (Young-Only Phase)
2. 공간 회수 단계 (Space-Reclamation Phase)

이 단계에서는 Eden과 Survivor 영역에서만 가비지 컬렉션을 수행하며, 살아남은 객체들은 Old 영역으로 이동함
✅ Young-only 단계에서 Space-reclamation 단계로 넘어가는 시점
Concurrent Star는 일반 Young GC처럼 동작하면서 동시에 마킹(Marking) 작업을 시작하는 특별한 Young GC
마킹(Marking)이란?
- Old 영역에서 살아있는 객체들을 확인하는 작업
- 살아있는 객체는 다음 단계에서 유지되고, 그렇지 않은 객체는 제거될 예정
- 하지만 마킹이 끝나려면 시간이 걸리므로, 이 과정에서 일반적인 Young GC가 계속 진행될 수도 있음
🚨 Concurrent Start 중 마킹을 취소하는 경우
Concurrent Start를 통해 마킹이 끝나면, Remark(재확인) 단계가 실행됨
이 단계에서는 마킹 결과를 확정함과 동시에 다음과 같은 작업이 수행됨
Cleanup 단계에서는 마킹된 정보를 바탕으로 Space-reclamation 단계로 넘어갈지 여부를 결정함
이제 Young GC뿐만 아니라 일부 Old 영역도 함께 정리하는 Mixed GC가 실행됨
이 과정에서 살아있는 객체들은 새로운 Old 영역으로 이동하고, 쓸모없는 객체가 많아진 Old 영역은 해제됨
하지만 이 과정도 무한정 반복되지는 않음
• G1은 “이제 Old 영역을 더 수집해도 효율이 없다!”고 판단하면 Space-reclamation을 종료
Space-reclamation 과정에서 메모리가 부족하면 어떻게 될까?
G1 GC는 Stop-the-World(STW) 방식으로 가비지 컬렉션을 수행함
즉, 가비지 컬렉션이 실행되면 애플리케이션이 일시적으로 멈추고, G1이 메모리를 정리한 후 다시 실행됨
🚨 Stop-the-World (STW)
JVM이 가비지 컬렉션을 실행할 때 애플리케이션의 실행을 잠시 중단하는 현상.G1은 라이브(live) 객체를 소스 영역(Source Region)에서 대상 영역(Destination Region)으로 복사하여 정리함
즉, 살아있는 객체는 다른 영역으로 이동하고, 필요 없는 객체는 버려진다는 뜻
객체가 이동하는 방식은 객체가 현재 위치한 메모리 영역(Region)에 따라 결정됨
✅ 일반 객체 (non-humongous objects)
즉, G1은 객체를 복사하면서 불필요한 객체를 자동으로 제거하고, 메모리를 효율적으로 재배치함
✅ 매우 큰 객체 (Humongous objects)
G1 GC는 가비지 컬렉션 시 객체를 이동시키는데, 이동 후 기존 객체를 참조하는 곳을 새로운 위치로 업데이트해야 함
이 작업을 효율적으로 수행하기 위해 Remembered Set(기억된 집합)이라는 구조를 사용함
✅ Remembered Set이 하는 일
즉, G1이 가비지 컬렉션을 수행할 때 다른 곳에서 Collection Set 내부 객체를 참조하고 있는 위치들을 미리 저장해두는 것이 Remembered Set의 역할
✅ Remembered Set의 구조
즉, 각 메모리 영역마다 해당 영역을 참조하는 외부 객체의 위치를 저장하는 Remembered Set을 관리하고, 가비지 컬렉션 시 이를 이용해 참조를 빠르게 업데이트하는 방식
Collection Set은 가비지 컬렉션을 수행할 메모리 영역(Region)들의 집합
즉, 이번 GC에서 정리할 대상이 되는 메모리 영역들의 목록
✅ Collection Set에 포함되는 영역들
이 Collection Set은 가비지 컬렉션을 진행하기 전에 선정되며, 특히 Remark Pause 단계에서 효율적으로 정리할 수 있는 영역을 미리 선정하는 것이 중요함
📌 TLAB이란?
- 각 스레드가 할당 속도를 높이기 위해 사용하는 작은 메모리 영역
- 가비지 컬렉션을 수행하기 전, 기존 할당된 TLAB을 해제하는 작업 필요
이 과정이 중요한 이유는 가비지 컬렉션을 병렬로 수행할 때 속도를 높일 수 있기 때문
여러 개의 Remembered Set을 하나로 합쳐 놓으면, 객체 이동 후 참조 업데이트하는 작업이 훨씬 빨라짐
📌 루트(Root)란?
- JVM 내부의 데이터 구조 (예: 스택, 정적 변수 등)에서 직접 참조하는 객체
- 코드에서 직접 참조하는 객체
- Heap 내부에서 다른 객체를 참조하는 객체
📌 과정
1. 루트에서 시작하여 살아있는 객체를 탐색
2. 살아있는 객체를 새로운 위치로 복사
3. 복사된 객체의 참조를 업데이트
4. 모든 루트를 처리할 때까지 반복
이 과정에서 Humongous 객체는 특별히 다루는데, 이동시키지 않고 필요할 경우에만 제거하는 방식으로 처리함
즉, 객체 복사가 끝난 후의 후처리 과정
이 과정이 끝나면 가비지 컬렉션이 마무리되고, 애플리케이션이 다시 실행됨
✔ Remembered Set
✔ Collection Set
✔ Garbage Collection Process (4단계)
1. Pre Evacuate Collection Set - 가비지 컬렉션 사전 준비
2. Merge Heap Roots - 여러 Remembered Set을 하나로 합쳐 중복 제거
3. Evacuate Collection Set - 객체를 복사하고, 참조를 업데이트
4. Post Evacuate Collection Set - 후처리 및 다음 애플리케이션 실행 준비