인사이트

인사이트리포트

디지털프렌스포메이션 최신 정보 및 트렌드를 제공합니다.

About G1 GC

2024.10.18김민경 프로
다운로드

들어가며

Java 8의 기본 Garbage Collector였던 CMS GC는 Java 9에서 deprecated되었고 Java 14에서 drop되었다. 본 문서에서는 CMS GC를 대체하는 새로운 기본 GC인 G1 GC가 CMS GC의 단점을 어떻게 보완하는지 알아보기로 한다.

 

1. 왜 G1 GC인가

1.1 CMS GC의 한계

CMS GC(Concurrent Mark-Sweep Garbage Collector)의 주 목적은 애플리케이션의 중단 시간을 최소화하여 성능을 개선하는 것이다.

  • CMS GC의 동작
    • Initial Mark: 짧은 시간 동안 애플리케이션을 멈추고(Stop-The-World; 이하 ‘STW’) 루트 영역에서 직접 참조되는 객체를 1차적으로 식별한다.
    • Concurrent Mark: 애플리케이션이 실행되는 동시에 힙의 모든 객체를 순회하여 사용 중인 객체를 식별한다.
    • Remark: Cuncurrent Mark 동안 참조가 변경된 객체를 STW 동안 재식별한다.
    • Concurrent Sweep: 살아있지 않은 객체의 메모리를 회수한다.

Remark 과정은 전체 힙 크기가 크거나 참조 관계가 복잡할수록 긴 STW를 필요로 한다. 또한 힙의 빈 공간을 효율적으로 처리하지 못해 파편화가 생기고, 이로 인해 메모리 압박이 심해지면 compaction을 위한 Full GC가 빈번히 발생할 수 있다.

 

2. G1 GC에서 달라진 점

이러한 CMS GC의 단점을 보완할 수 있는 G1 GC(Garbage-First Garbage Collector)의 특징이 있다.

2.1 Region-based Management

G1 GC는 힙을 일정한 크기의 리전(Region)으로 분할한다. 각각의 리전은 Young 또는 Old Generation이 될 수 있고, 하나의 리전이 GC가 수행되는 최소 단위가 된다. G1 GC는 이 리전들을 가비지의 양과 종류에 따라 우선순위를 두어 효율적으로 처리한다.

리전은 통상의 GC와 마찬가지로 young generation, old generation으로 나뉘며 이들 영역의 위치는 정해져 있지 않고 메모리 상태에 따라 유동적으로 정해진다.

  • Young generation
    • Eden: 객체가 최초에 생성되는 영역
    • Survivor: Eden에서 생존한 객체가 이동되는 영역
  • Old generation
    • 일정 시간 이상 살아남은 객체가 이동되는 영역
  • Humongous
    • 리전 크기의 절반 이상인 거대한 객체가 할당되는 영역

실제로 GC 작업이 수행될 때, GC를 수행할 리전의 집합을 Collection Set(이하 ‘CSet’)으로 정의한다. CSet은 메모리 상태를 최적화하고 GC 효율성을 높이기 위해 동적으로 결정된다.

 

2.2. Evacuation

G1 GC는 GC 과정에서 살아남은 객체를 새로운 위치로 대피(evacuate)시킨다. Evacuation은 Young generation의 Eden-Survivor0-Survivor1 영역 간에 일어나 이전 영역을 가비지 처리하는 동작에도 발생하고, Old generation에서도 살아남은 객체를 대피 시켜 메모리 파편화를 줄이고 전체적인 메모리 효율성을 향상 시킨다.

3. G1 GC의 동작

G1 GC는 크게 두 가지 단계로 구성된다. Young 객체를 확인하고 old generation으로 승격시키는 young-only phase와 실제로 공간 회수를 수행하는 space-reclamation phase를 실제 GC log와 함께 알아보자.

3.1 Young-only phase

3.1.1 Young GC

Young-only phase는 young 객체를 old generation으로 승격 시키는 Normal young GC 작업으로 시작한다. 참조가 유효하여 살아남은 young 객체는 Eden->Survivor#, Survivor0<->Survivor1, Survivor#->Old 의 방향으로 이동하게 된다.

  • Young generation CSet: Eden, Survivor0, Survivor1에서 GC가 필요한 리전을 포함한다.

 

3.1.2 Concurrent Mark

Young GC 후에 old generation 점유율이 임계값을 넘어서면 concurrent start를 트리거한다.

  • Concurrent Start: 이 단계에서는 실제로 old generation의 메모리를 회수하진 않지만 이후의 회수 단계에서 생존할 살아있는 객체를 식별한다. 루트 영역으로부터 살아있는 객체 탐색은 STW 없이 진행된다.
    • 로그상 Concurrent Start와 Concurrent Cycle은 서로 다른 GC 순번을 가지고 있으나 동일한 트리거로 수행된다.
    • Remark: Concurrent Mark 중에 변경된 참조를 반영하여 재탐색한다. STW가 발생한다.
    • Cleanup: Mark 결과를 바탕으로 old generation의 메모리를 정리하고 회수할 준비를 한다. 실제로 메모리 회수가 필요하다고 판단될 때 Mixed GC를 트리거한다.

 

3.2 Space-reclamation phase

3.2.1 Prepare Mixed

Young, old generation 모두를 대상으로 하는 Mixed GC를 준비한다.

 

3.2.2 Mixed GC

Young, old generation에서 동시에 가비지를 탐색하며, 살아있는 객체를 이동시키거나 죽은 객체를 old generation에서 제거한다.

  • Old Generation CSet: Old generation에서 GC가 필요한 리전을 포함하며, mixed GC 또는 full GC 시에 정의된다.

 

3.2.2 Full GC

Young GC에서 young 객체를 old로 이동시킬 수 없을 만큼 old generation의 메모리가 부족하거나, old GC(mixed 또는 full GC) 수행 후에도 old generation의 메모리를 확보할 수 없을 때 full GC가 발생한다. 이때는 heap compaction으로 가용 메모리를 확보한다.

통상적으로는 old GC로 old generation이 확보되므로 full GC가 트리거되는 경우가 많지 않으나 메모리 회수보다 빠르게 너무 많은 객체가 할당될 때, 거대한 객체가 많이 할당될 때, 메모리 누수가 발생할 때 등 여러 경우에 full GC가 발생할 수 있다.

 

4. G1 GC options

G1 GC는 특별한 옵션을 사용하지 않아도 전반적으로 좋은 성능을 제공한다. 애플리케이션의 목적에 따라 몇 가지 옵션을 추가할 수 있다.

 

4.1 거대한 객체의 수를 조절하려면

G1 GC에서 리전 크기의 절반을 넘는 거대한 객체는 humongous region에 할당된다. Humongous 객체가 많으면 이를 처리하기 위해 더 많은 메모리 영역을 할당하고 관리해야 한다. 메모리 압축(compaction) 과정이 어렵고 시간이 오래 걸릴 수 있다.

GC log를 살피면 이 거대한 객체가 차지하는 영역의 양을 알 수 있다.

리전 크기(기본값: 1M)를 늘리면 기존에 humongous로 할당되던 객체가 더 이상 humongous가 아니게 될 수 있다. 이 변경은 메모리 사용에 직접적인 영향을 미치지는 않으나 새로운 객체의 할당 방식과 GC 과정에 영향을 미치게 된다. Humongous region 자체는 줄어들 수 있으나 메모리 파편화의 위험성이 커지고, 특히 메모리 사용 패턴이 일정하지 않은 애플리케이션은 메모리 사용이 더 비효율적이 될 수도 있다. 또한 GC가 한 번에 처리해야 할 영역의 크기가 커지는 것이므로 더 많은 시간이 소모될 수도 있다. 따라서 애플리케이션의 메모리 사용 방식을 고려하여 값을 지정하여야 한다.

 

4.2 최대 정지 시간을 조절하려면

Max pause 시간을 조절하여(기본값: 200밀리초) 지연 시간을 최소화하거나 반대로 시간이 걸리더라도 한 번에 많은 처리를 할 수 있다.

 

4.2.1 Young generation 크기 설정은 하지 않는다

최대 정지 시간을 설정했다면 G1 GC는 자동으로 young generation의 크기를 결정하게 된다.  만약 이 옵션을 명시할 경우 최대 정지 시간 옵션이 정상적으로 작동하지 않는다.

 

4.3 Mixed GC의 작업량을 조절하려면

Mixed GC가 한 번 수행될 때 처리할 리전의 개수(기본값: 8)를 조절한다. 이 값이 줄어들면 1회의 Mixed GC가 빠르게 끝나므로 가용 메모리를 빠르게 확보할 수 있으나, 전체 영역을 처리하려면 Mixed GC가 여러 번에 거쳐 수행되므로 STW 시간이 더 길어질 수 있다.

반대로 이 값이 커져 만약 최대 중단 시간(MaxGCPauseMillis) 내에 처리할 수 없다면 MaxGCPauseMillis 값이 우선 시 된다.

 

 

마치며

최근에는 하드웨어의 발전으로 대형 엔터프라이즈 시스템에서도 자바가 많이 쓰이고 있다. 이에 따라 적절한 GC의 선택과 사용 또한 중요해진다.

G1 GC는 중단 시간(STW)을 최소화하고 메모리 파편화를 방지할 수 있어 현장에서 널리 사용되고 있는 만큼, G1 GC에 대한 깊은 이해는 여러분의 시스템 성능을 한층 높이는 데 도움이 될 것이다.

# References

https://docs.oracle.com/en/java/javase/11/gctuning/garbage-first-g1-garbage-collector1.html#GUID-0394E76A-1A8F-425E-A0D0-B48A3DC82B42
https://docs.oracle.com/en/java/javase/11/gctuning/garbage-first-garbage-collector-tuning.html#GUID-90E30ACA-8040-432E-B3A0-1E0440AB556A
https://www.redhat.com/en/blog/collecting-and-reading-g1-garbage-collector-logs-part

김민경 프로

김민경 프로

플랫폼사업팀

에스코어의 CDC 솔루션 8Sync의 품질 점검 및 기술지원 업무를 담당하고 있습니다.

연관 아티클

  • 데이터 기반 경영관리 선행조건 마스터 데이터 표준화 & 운영정보 최적화
    데이터 관리2024.10.24

    데이터 기반 경영관리 선행조건 마스터 데이터 표준화 & 운영정보 최적화

    자세히 보기
  • UX 최적화로 업무 효율성 향상
    2024.10.22

    UX 최적화로 업무 효율성 향상

    자세히 보기
  • LangChain의 새로운 라이브러리 LangGraph 훑어보기
    SW 테크놀로지2024.10.17

    LangChain의 새로운 라이브러리 LangGraph 훑어보기

    자세히 보기