[GabageCollection] 가비지 컬렉션 알고리즘 종류와 구조

2024. 8. 20. 00:18Lang/JAVA

흔히 Java를 사용할 때의 장점을 말할 때 GC(GabageCollection)이 자주 나온다.

 

메모리 관리를 Java에 내장된 GC가 자동으로 해주면서

개발자들이 일일이 메모리 관리에 시간을 쓸필요가 없기 때문이다.

 

( Java 이전의 언어들은 GC 같은 기능을 제공해주고 있지 않으나 파이썬이나 Node.js 계열 같이 자바 이후로 두각을 보이는 언어는 모두 자체적으로 메모리 관리 기능이 있다고 한다.)

 

오늘은 GC에 대한 정리를 하려한다.

 



Gabage Collection

 

GC(Gabage Collection)는 C언어 등에서 처럼 객체의 메모리를 직접 삭제해주는 로직이 없어도 자동으로 사용되지않는 객체에 할당된 메모리를 삭제해주는 역할을 한다.

 

여기서 메모리는 JVM의 힙(heap) 영역을 가리킨다.

 

힙(heap) 영역은 물리적으로 Young 과 Old로 나눠져있다

Young과 Old 메모리에 할당된 부분 중 사용되지않는 부분을 청소해주는 게 GC의 주요 기능이라 할 수있겠다.

 

GC는 크게 두가지 과정으로 이루져있다.

 

1. Mark (표시): 먼저 GC는 메모리에 할당된 모든 객체들을 추적하여, 참조되고 있는 객체는 '사용 중'으로 표시하고, 그렇지 않은 객체들은 '사용되지 않음'으로 표시한다. 이 단계에서 객체들이 더 이상 사용되지 않는다고 판단되면, 해당 객체들은 수집 대상이 된다.

2. Sweep (청소): '사용되지 않음'으로 표시된 객체들은 메모리에서 제거된다. 이 과정에서 Young 영역에서는 주로 Minor GC가 발생하고, Old 영역에서는 Major GC가 발생한다. Minor GC는 주로 짧은 시간 동안 살아남은 객체들을 청소하며, Major GC는 상대적으로 더 오래 살아남은 객체들을 대상으로 청소한다.

 

 

 



GC 알고리즘

 

1. Serial GC

  • 설명:
    • 단일 스레드를 사용하여 GC 작업을 수행
    • Young 영역과 Old 영역 모두에서 GC가 수행
    • GC가 동작하는 동안 애플리케이션의 모든 스레드가 중단
  • 특징 (적합한 환경)
    • 메모리 크기 -> Low ↓
    •  CPU 코어 -> Low ↓      
  • 단점: 모든 GC 작업이 단일 스레드로 수행되기 때문에 대규모 애플리케이션에는 적합하지 않다.

2. Parallel GC

  • 설명:
    • 여러 개의 스레드를 사용하여 GC 작업을 병렬로 수행
    • Serial GC와 유사하게 Young 영역과 Old 영역에서 GC가 발생 => But, 병렬로 수행됨으로써 GC 시간을 단축
  • 특징:
    • 멀티코어 환경 -> 효율 Up↑
    • 응답성보다 처리량이 중요한 애플리케이션에 적합
  • 단점: GC 도중 애플리케이션 스레드가 여전히 중단 ( Serial, Parallel 또한 마찬가지)

3. CMS GC (Concurrent Mark-Sweep)

  • 설명:
    • 애플리케이션의 정지 시간을 최소화하기 위해 설계
    • Mark 단계는 애플리케이션 스레드와 병렬로 실행
    • Sweep 단계에서 짧은 시간 동안 애플리케이션이 중단
  • 특징: 낮은 지연 시간이 중요한 애플리케이션에 적합
  • 단점: **메모리 파편화가 발생할 수 있으며, 메모리 부족으로 인한 Full GC가 발생할 수 있다.

** 메모리 파편화: 메모리 공간이 군데군데 잘게 나뉘어져서, 큰 데이터를 저장할 수 있는 연속된 빈 공간이 부족해지는 현상

4. G1 GC (Garbage First)

  • 설명:
    • 대규모 힙 메모리를 효율적으로 관리하기 위해 설계
    • 힙 메모리를 여러 개의 영역으로 나눔
    • 가비지가 많은 영역부터 청소하는 방식으로 동작
  • 특징:
    • 예측 가능한 짧은 GC 정지 시간이 목표
    • 큰 힙 메모리를 사용하는 애플리케이션에 적합
  • 단점: 튜닝이 다소 복잡할 수 있으며, 모든 시나리오에서 가장 빠른 GC는 아님

5. ZGC (Z Garbage Collector)

  • 설명:
    • 매우 낮은 GC 정지 시간을 목표 ( 정지 시간 최소화가 목표 )
    • 10ms 이하의 정지 시간을 보장하며, 큰 힙에서도 동작
    • GC 작업의 대부분이 애플리케이션 스레드와 병렬로 실행
  • 특징:
    • 초대형 힙 메모리짧은 응답 시간이 중요한 애플리케이션에 적합합
  • 단점: 비교적 최신 기술으로 검증이 부족

6. Shenandoah GC

  • 설명:
    • Red Hat에서 개발한 GC
    • 매우 낮은 GC 정지 시간을 목표 ( ZGC와 유사)
    • 힙 메모리의 크기와 상관없이 짧은 응답 시간을 유지하는 데 중점
  • 특징:
    • 낮은 지연 시간이 중요한 애플리케이션에 적합
    • ZGC와 마찬가지로 애플리케이션 스레드와 병렬로 작업
  • 단점: 특정 JVM 환경에 최적화되어 있어 모든 환경에서 지원되지 않을 수 있음

=> 결론 :

1. 힙 메모리가 충분하다면 -> ZGC

2. 힙 메모리가 충분치는 않지만 성능이 우선이라면 -> Shenandoah GC

3. 힙 메모리가 충분치는 않고 Shenandoah GC를 쓰기 어려운 JVM 환경이라면 -> G1 GC

4. 적은 어플리케이션 규모라면 ->CMS GC, Parallel GC 

 

-- 경험 --

: Parallel GC를 사용해 봤는데 young 영역의 sweep 시간은 매우 짧아서 UI/UX에 영향을 주지 않을 정도였지만 간헐적인 old 영역의 sweep를 위한 pause가 상당히 장시간이 걸렸다. 내 경우엔 시간 단위 였기때문에(서비스에 크리티컬한 문제) 당장 분산처리가 불가한 상황에서 튜닝이 필요하다면 다른 알고리즘을 추천한다.