Garbage Collector : Generation GC, G1 GC, ZGC

2025. 5. 15. 10:14
반응형
Garbage Collection Guide

들어가기 전에

저번 글에서 가비지 컬렉터 ( GC ) 의 개념과
GC 가 객체를 삭제하는 여러가지 알고리즘에 대해 알아보았다.

이번에는 GC 의 동작 방식과 GC 의 종류에 대해서 알아보려고 한다.

GC Remind - 1 : GC 란 무엇인가?

Garbage Collector : 더이상 참조하지 않는 객체를 제거하여 자동으로 메모리를 관리하는 프로세스

GC 덕분에 메모리 누수에 대한 걱정을 덜 수 있으며

Java, Python, JavaScript 등의 언어에 내장되어 있다. ( C, C++ 은 개발자가 직접 메모리 관리 )

하지만 GC 는 언제 작동하는지 정확히 알 수 없으며
GC 가 동작하는 동안 다른 Thread 의 동작이 멈추는 현상 ( STOP THE WORLD ) 이 발생 할 수 있다

그래서 너무 자주 실행되면, 프로그램 성능에 영향을 미칠 수 있다.


✅ 정리하자면

GC : 자동으로 참조하지 않는 객체를 제거하여 메모리를 관리하는 프로세스

장점

  • 메모리 누수 관리를 직접 하지 않아도 된다.

단점

  • GC 가 언제 작동하는지 정확히 알 수가 없다.
  • GC 가 동작하는 동안 JVM 동작을 멈추고, 자주 사용하는 경우 성능에 영향을 미친다.

✅ 알아둬야할 내용

GC Root : 현재 프로세스에서 참고하고 있는 객체를 의미

메모리 단편화 : 사용하지 않는 메모리 영역이 연속적이지 않은 상태


image.png

GC Remind - 2 : GC 의 다양한 알고리즘

더이상 참조 하지 않는 객체들의 메모리를 회수하는 다양한 방식이 있었고, 4가지 방식에 대해 알아 보았다.


1. Mark & Sweap

동작 방식 : GC ROOT 에 도달가능한 객체 Mark → 나머지 객체 메모리 해제 Sweap

장점

  1. 순환참조 처리가능

문제점

  1. 메모리 단편화가 발생하고 ( 메모리 빈공간이 퍼져있음 )
  2. Stop-The-World 길다.

2. Mark & Compact

동작 방식 : MarkSweap → 메모리 단편화를 방지하여 사용 중인 메모리를 한쪽에 압축 Compact ( 단편화 방지 )

장점

  1. 단편화 문제 해결

문제점

  1. 객체 이동 시키는 비용이 크다
  2. GC 성능 저하가 일어난다.

3. Mark & Copy

동작 방식 : Mark 된 객체만 복사 하고 남은 메모리들 초기화

장점

  1. Sweap 하는 단계 생략 가능 → 성능 개선

문제점

  1. 메모리 낭비가 심함 ( 항상 복사하기 위한 메모리 공간 남겨두어야 한다. )

4. Reference Counting

동작 방식 : 객체 마다 참조수를 관리하고, 참조 수가 0 이되면 제거

장점

  1. 즉시 메모리 회수 가능

문제점

  1. 순환 참조 처리 불가 ( 서로 참조하면 0 이 되지 않음 )
  2. 참조하는 수 관리 오버헤드가 크다.

이렇게 발전해도 공통적인 문제점은 남아 있었다.
Stop-The-World 시간이 길었고
대부분의 객체는 생성 후 금방사라지는데, 모두 동일한
방식을 사용하다 보니 비효율 적이였고
위의 GC 들은 단일 스레드 기반이라 멀티 코어 자원을 활용하지 못하는 등의 단점이 있었다.


✅ 정리하자면

위의 GC 들의 공통적인 문제점으로

  1. Stop-The-World 시간이 오래 걸림
  2. 객체들의 생명주기가 대부분 짧은 것에 비해, 동일하게 GC 가 적용되니 비효율 적
  3. 단일 스레드 기반으로 개발 되다 보니, 멀티 코어에서 활용하기 어려움

등의 문제를 가지고 있다

Generation GC

객체의 생명주기를 기반으로 메모리를 Young Generation, Old Generation 으로 나누어 관리하는 방식

세대별로 나누어 메모리를 관리하여, 생명 주기에 따라 다르게 관리할 수 있다.

대부분의 객체는 금방 GC 의 제거 대상이 되고 ( Unreachable ), 오랫동안 남아있는 객체는 드물게 존재한다.( Weak Generation Hypothesis )

image.png


Young Generation

빈번하게 GC 가 일어나는 영역으로, 짧은 생명주기의 객체를 제거하는 영역

- Eden
객체가 처음 생성되면 할당되는 곳이다.
- Servivor Space ( S0, S1 )
Minor GC 에서 살아남은 객체가 이동한다.
S0,S1 영역이 있으며 번갈아가며 사용된다. ( 한쪽은 반드시 비어있어야함 )


Old Generation

YG 에서 오래 생존하여 승격된 객체가 저장되는 영역, FULL GC 또는 Major GC 가 발생

여기서 말하는 Minor GC, Major GC 또는 FULL GC
각각 YG에서 일어나는 GC, OG 에서 일어나는 GC 를 의미한다.


동작 방식 ( Minor GC )

  1. 객체가 Eden 영역에 생성

    → 모든 객체는 처음 생성 시 Eden 영역에서 생성

  2. Minor GC 가 발생

    → Eden 영역에 객체가 가득 차면 Minor GC 발생 , Live 객체를 Mark 하고 새로운 Survivor 공간으로 복사 ( Mark & Copy )

  3. Survivor 에서 새로운 Survivor 영역으로 객체 복사

    → 객체를 복사하여 하나의 영역만 사용하도록 설정

  4. Eden 영역과 사용하던 Survivor 영역 초기화

    → 사용했던 영역 초기화 및 새로운 Survivor 영역의 Age 값 1 증가


동작 방식 ( Major GC )

  1. YG 의 Survivor 영역으로 부터 객체를 받는다.

    → YG 의 AGE 가 특정 수를 넘으면 이동 OG 로 이동

  2. Old 영역에 객체가 가득 차면 Major GC 또는 FULL GC 가 발생

    → Major GC 실행 중 Stop-The-World 발생 우려가 있다.


장점

  • 생명주기가 짧은 객체를 빠르게 제거 가능 ( 성능 향상 )
  • Young/Old 영역 별 최적화된 알고리즘 적용 가능

단점

  • Old Genration 의 Full GC 는 성능 저하를 가져올 수 있음

최근에 사용되는 GC 알고리즘

이제 최근에 사용되는 GC 알고리즘에 대해서 알아볼 생각이다.
특히 JVM 에서 사용되는 알고리즘 대해서 알아보자

G1GC

image.png

Garbage-1(First) Garbage Collector
: Heap 을 Region 으로 나누어 메모리의 역할을 동적으로 부여하는 방법을 사용 하는 GC

- Java 9 부터 JVM 기본 GC
- 높은 처리량과 낮은 지연시간을 추구

G1 이 Garbage-First 인 것 처럼, Garbage 가 많은 Region우선적으로 수집하여 효율적이다.
여기서 Region 이란 Heap 메모리를 1MB ~ 32 MB 의 고정된 크기로 나눈 영역 (JVM 이 자동 결정 )을 말하며
동적으로 아래의 여러가지 역할을 부여하는 방식을 사용한다.

  1. Eden

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

  2. Survivor

    : YG 의 Minor GC 에서 살아남은 객체가 저장되는 영역 - YG

  3. Old

    : 오래 살아남아 승격된 객체가 저장되는 영역 - OG

  4. Humongous

    : Region 의 50% 이상 차지하는 객체가 저장되는 영역

  5. Free

    : 아직 아무 역할도 할당되지 않는 영역

이렇게 역할을 나누어, 필요할 때마다 Free 인 Region 에
새로운 역할을 부여하여 사용할 수 있으며 동적으로 변경 될 수 있다.

Region 을 사용하여 메모리를 독립적으로 관리함으로써, 메모리 단편화를 줄일 수 있고 효율적으로 사용이 가능하다.
Remembered Set 을 사용하여 자신을 참조하는 포인터를 기억하기 때문에
GC 참조 확인 시 전체 스캔 없이 빠르게 접근이 가능하다.


G1 GC 의 GC 타입

1. Minor GC
: YG 에서 발생하며 Mark&Copy 로 빠르게 수행됨

2. Major GC
: OG 에서 발생하며, 전체 OG 영역을 정리하던 것과 달리 OG 역할을 하는 Region 에 수행

3. Mixed GC
: YG,OG 영역 중 일부를 함께 수집
Eden ( Minor GC ) 수행OG 탐색 및 대상 선택OG 일부 Region 수집

여기서 Mixed GC 는 YG,OG 의 객체를 함께 수집하는 방식 으로,
기존의 Major GC ( Full GC ) 의 경우, OG 의 객체를 탐색하고 삭제하는데 시간이 오래 걸린다. ( STW 이 오래걸림 )

그래서 G1 GC 의 특징 중 하나인 Region을 사용하여 Garbage 비율이 높은 Region 을 선별적으로 수집하여 GC 를 수행한다.
즉, Minor GC 와 일부 Region 에 대한 Major GC 를 수행하는 것을 말한다.


JVM 튜닝 Option

-XX:MaxGCPauseMillis : GC 정지 시간 최대 설정
-XX:InitiatingHeapOccupancyPercent : Old 영역의 GC 트리거 시점 (% 기준)

위와 같은 설정으로 STW 의 최대 시간은 물론
CG 가 수행 되는 조건을 설정 할 수도 있다.

✅ G1 GC 정리하자면


정의

G1 GC 는 메모리를 Region 이라는 단위로 나누어 GC 를 수행하는 방법


특징

Heap Size 가 6 ~ 32 GB 인 경우 적합


Region

Heap 을 JVM 에 의해 고정된 크기로 나눈 영역

  • EDEN, SURVIVOR, OLD, HUMONGOUS, FREE 역할을 할당받아 사용
  • 동적으로 역할이 할당 됨
  • Remembered Set 을 사용해 다른 Region 을 추적하여, GC 확인 비용 감소

Mixed GC

Minor GC 와 일부 Region 의 Major GC 를 수행

  • STW 를 줄일 수 있음
  • GC 효율 향상

장점

  • 최대 정지 시간 설정 가능
  • Region 단위 메모리 관리로 단편화 방지
  • Multi Thread 를 이용한 병렬 처리 가능
  • GC 효율성 향상 및 Full GC 최소화

단점

  • GC 튜닝이 어려움
  • 높은 CPU 오버헤드 ( Remembered Set 를 동시마킹 )

ZGC

img1.daumcdn.png

ZGC ( Z Garbage Collector ) : Stop-The-World 을 밀리초 단위로 제한하는 고성능 GC

- Java 11 에서 실험적으로 도입하여, Java 15부터 사용 가능하다
- 초저 지연 ( 10ms ) 유지 , 대용량 Heap 에 적합
- 대규모 HEAP 지원 ( 최대 4TB )
- GC 작업 대부분을 애플리케이션 스레드와 동시적으로 처리
- ZPage 라는 Region 을 구분하지만 세대 구분 없이 다양한 크기를 동적으로 할당

ZGC 는 G1 과 달리 GC Stop-The-World 를 최소화 하는데 집중하며,
대부분의 GC 작업을 STW 없이 수행하는 것이 특징이다. G1 과 같이 메모리를 특정 영역으로
구분하여 사용하는데 고정적인 메모리로 나누는 것과 달리 다양한 크기의 메모리를 할당하며,
세대 구분을 하지 않는다.

ZGC 는 객체의 이동이나 수집 등을 어플리케이션과 동시에 수행 할 수 있도록
Colored Pointer 를 사용한다.
64 비트 메모리 주소를 사용하여 객체 포인터에 추가적인 메타데이터를 저장하며,객체 참조 영역을
색깔로 구분하고 ZGC 의 핵심 기술이다.


ZPage

ZGC 에서 Heap 메모리를 나누는 논리적인 단위 ( small : 2MB, Medium: 32MB, Large : 동적 크기 )

  • 객체의 크기에 따라 동적 할당 된다
  • Small/Medium 은 여러 객체, Large 는 단일 큰 객체 ( 대형 배열 ) 에 저장

G1 GC 의 Region 과 달리 객체의 크기에 맞게 동적으로 할당한다. ZPage 의 Larage 의 경우
하나의 객체만 저장하여 단편화를 방지하는데 효과 적이다.


Colored Pointer

보통 64비트 중 최상위 4비트를 메타데이터로 사용하여 객체 상태를 관리하는 기술
메타데이터에 데이터를 저장하고, GC 작업을 지원한다.

구조

  • 4 비트 메타데이터
  • 42 비트 주소 : 실제 객체 위치
  • 18 비트 예약 : 미래 확장용

메타데이터 구성

  • Marked0/Marked1

    객체가 참조 되어 있는지 두 개의 마킹 비트를 사용

  • Remapped

    객체가 새로운 메모리 위치로 이동 되었는지 확인

  • Finalizable

    객체가 finalize() 를 호출해야하는지 여부


Load Barrier

ZGC 에서 객체 참조를 읽을 때 실행되는 검사 메커니즘
어플리케이션이 객체 포인터를 읽을 때 마다 메타데이터 검사하여 GC 작업을 지원

  • 객체 참조를 읽을 때 동작함으로 STW 없이 동시에 동작한다
  • 참조를 읽을때 수행 작동함으로 CPU 사용량이 증가한다.
  • Colored Pointer 를 사용하여 별도 구조 없이 객체 상태를 관리한다.

ZGC 동작 순서

🟡 1. Initial Mark (STW)

GC 사이클 시작 단계로, GC Root에서 직접 참조하는 객체들만 마킹 ( 잠시 STW 발생 )


이 시점에 ZPage 식별,
Colored Pointer에 Marked0, Marked1 등의 마킹 상태 비트 설정

🟢 2. Concurrent Mark

Application 스레드와 동시에 동작하면서,
루트 객체로부터 연결된 모든 객체를 따라가며 Live Object 마킹
Colored Pointer : 객체의 상태(Marked, Relocated 등)를 포인터 비트에 저장해 빠르게 확인 가능
Load Barrier : 객체 접근 시 상태를 확인하고 필요 시 GC 관련 동작을 삽입
→ 덕분에 STW 없이도 안전하게 마킹 가능

🔵 3. Concurrent Prepare for Relocation

살아있는 객체 중 이동 대상이 될 객체를 선정하고,


새 메모리 주소(ZPage 내) 할당 및 이동 계획 수립

🔴 4. Concurrent Relocate

GC가 백그라운드에서 객체를 새로운 주소로 복사 이때 객체를 참조하려 하면,
Load Barrier가 현재 포인터 상태를 확인하고 새 주소로 리디렉션 처리


애플리케이션은 객체가 이동 중이어도 안정적으로 접근 가능
Full STW 없이도 안전한 Compact 가능

🟣 5. Final Remap (STW)

일부 남아 있는 참조 주소 갱신
짧은 STW 발생 (몇 ms 수준)
이후 GC 사이클 종료

✅ ZGC 정리하자면


정의

초저 지연 및 대용량 HEAP 을 제공하는 GC


특징

  • HEAP 은 최대 4TB 까지 지원 가능 하다.
  • ZPage 라는 동적인 HEAP 구조를 가진다.
  • Application 이 객체 참조 시 병렬적으로 GC 가 발생한다.
  • Colored Pointer 를 사용하여 메타데이터를 사용하여 오버헤드가 적다.

장점

  • 초저 지연 STW 를 경험 할 수 있다.
  • 대용량 처리에 적합하다.
  • Application Thread 와 병렬적으로 GC 가 일어난다.
  • 오버헤드가 적다
  • 대용량 데이터의 단편화가 적게 일어난다.

단점

  • 객체 참조를 읽을 때, Load Barrier 가 작동하여 CPU 사용량이 늘어난다.
  • Colored Pointer 가 64 bit JVM 에서만 지원되기 때문에 사용에 제한적이다.
  • 튜닝하는데 복잡하다

글을 마치며

이번 글 까지 작성한 덕분에 GC 에 대한 개념을 잡아 갈 수 있었다.

G1 GC 와 ZGC 를 비교해 보는 것도 좋은 방법이 될 것 같다.

반응형

BELATED ARTICLES

more