본문 바로가기

JAVA

JAVA의 GC

기본 개념

  • Java Platform의 핵심 기능
  • 자동 메모리 관리
    • 빠른 메모리 할당
    • 효율적인 회수
  • 다양한 사용 사례 제공
    • 배치 처리
    • UI application
    • 작은 cloud service

GC는 왜 여러개가 있을까?

GC들마다 알고리즘적인 차이가 존재. 프로그램의 특성별로 GC 선택도 달라져야 할 것. (default는 G1 임)

[!note]
오라클 블로그에서 java 8 ~ java 18까지의 GC 발전과 여러 GC 차이점을 설명하고 있음

메모리 회수 (Memory Reclamation)

Liveness Determination

  • 어떤 객체가 쓰레기(메모리가 회수가능한) 값인지 판단하는 과정
  • JAVA의 GC는 Object Graph를 tracing(추적)하여 이 과정을 처리함

Reclaiming memory

메모리 회수 알고리즘에는 여러개가 존재함

자바의 GC 구조는 일반적으로 아래와 같음

→ 개발자는 G1 GC , Parallel GC , ZGC 같은 큰 범위인 GC 종류를 선택하면
GC가 메모리 회수 알고리즘을 뭘 선택할지는 JVM에 맡김

Mark-Sweep Algorithm

  • 작동 원리
    • Mark (표시)
      현재 참조하고 있는 객체들을 표시
    • Sweep (제거)
      더 이상 표시(참조)되지 않는 객체를 제거하여 메모리를 회수함

이때, 참조하고 있는 객체들을 파악하기 위해서 필요한것이 Object Graph임
이를 통해 객체간의 관계를 추적해서 이 알고리즘을 처리할 수 있음

  • 장점
    • 구현이 간단함
    • GC 처리동안 메모리간의 이동이 필요 없음
  • 단점
    • Memory fragmentation(메모리 단편화)가 발생함

Mark-Compact Algorithm

  • 작동원리
    • Mark-Sweep 알고리즘을 그대로 사용하되 해당 알고리즘이 끝나면 빈 메모리를 한쪽으로 compact(압축)함
  • 장점
    • Mark-Sweep 알고리즘을 그대로 차용하되, 메모리 단편화를 방지할 수 있음
  • 단점
    • GC 처리동안 메모리간의 이동이 발생함

Copying Algorithm

  • 작동원리
    • 메모리를 두 군데 (From, To)로 나누고 한쪽에서만 객체를 생성하다가 GC가 발생하면 살아있는 객체만 From에서 To로 복사하고 From은 비움
  • 장점
    • memory fragmentation이 없음
    • 복사만 하므로 빠름
  • 단점
    • 메모리를 from, to 두군데를 사용하므로 메모리 공간 낭비임
    • 큰 heap에서는 비효율적임
      Copying Algorithm은 전체 heap 메모리를 반으로 나눠서 From, To 로 나눠버림
      따라서 예를 들면 8GB라면 4GB만 사용할 수 있는 진짜 메모리(From)임

GC 작동 시점

Stop-the-world

모든 자바 스레드를 멈추고 GC를 실행

Concurrent collection

자바 스레드 작업과 동시에 같이 GC를 실행

Generation Collection

효율적인 GC를 만들기 위한 기술
Java 팀에서는 “Generation hypothesis (세대 가설: 대부분의 객체는 짧은 기간동안만 사용된다는 가설)”을 기반으로 GC를 효율적으로 만들기 위해 노력중
heap memory를 Young Generation과 Old Generation 으로 분리하여 새로 만들어진 객체는 Young Generation에 배치한 후 관리함. 이때 Young Generation 대상만 GC를 자주 실행함

GC 선택 기준

Throughput (처리량)

일정 시간 당 처리한 트랜잭션 수

Latency (지연시간)

한 트랜잭션동안 걸린 시간

Footprint (자원)

GC 로 인해 사용되는 CPU 및 메모리 자원

[!tip]
이 중 하나를 중점적으로 택하고 그에 맞는 GC를 선택하는게 맞다.

GC 종류

GC Focus area Support
Serial Memory footprint (메모리 자원 중시) OpenJDK, Oracle
Parallel Throughput (처리량 중시) OpenJDK, Oracle
G1 Balanced performance (균형잡힌 성능) OpenJDK, Oracle
ZGC Low latency (낮은 지연속도) OpenJDK, Oracle
Shenandoah Low latency (낮은 지연속도) OpenJDK
  • Serial GC
    구현방식이 단순하고 GC 가 필요한 추가적인 메모리 사용량이 낮으므로 메모리 오버헤드가 낮음.
    Java 어플리케이션 스레드를 중단하고 GC를 단일 스레드로 수행하므로 큰 heap memory일 경우 최적의 방법이 아닐수는 있지만 작은 단위의 서비스 경우 괜찮은 대안일 수 있음.

  • Parallel
    Serial GC 와 거의 비슷하지만 GC를 멀티쓰레드를 사용해 병렬처리로 수행함
    JDK 8까지 default GC 였음

  • G1
    Throughput + Latency 의 균형을 잡은 GC
    Stop-the-world + Concurrent GC 혼합된 방식
    • 작동방식
      1. Old Generation의 생존 여부를 Java Appliction과 동시에 Marking 하고
      2. Mixed GC (Young + Old Generation 일부 를 같이 수집하는 방식) 를 여러번에 거쳐 수행함
    위처럼 stop-the-world 방식을 사용하되 Old Generation 여러번에 나눠서 수집하는 방식을 택하며 긴 GC Latency를 방지함. 이때 지연시간을 G1 GC는 측정 및 조정이 가능함.

    JDK9 ~ 부터 default GC 임

  • Object Graph
    객체들간의 관계를 파악하기 위해 만들어놓은 객체 탐색(DFS Depth-First Search: 아래로 내려가며 찾는 그래프 탐색 알고리즘)을 통해 만들어진 그래프

    Root Object → 객체 → 객체 → … 형식으로 되어있음. Root Object 로부터 참조된 객체,요소들을 따라감. 이때 참조가 끊어진 객체들을 garbage로 취급하게 된다

 

  • G1 GC 의 메모리 회수 전략
    1. 전체 heap memory를 region 단위로 나누고,
    2. young generation은 Copying 회수 방식 채택,
    3. old generation은 Mark-Compact 방식 채택함
    즉, 논리흐름은 지금 heap에 여유가 있나?이 region이 얼마나 오래되었는가? 와 같은 흐름을 따름

 

  • Generation
    Heap 메모리에 영역을 나누어 객체들을 관리함
    GC 성능을 높이기 위해 전략적으로 나눈 “영역” → “최적화”

    새로운 객체 및 짧은 생명의 객체 → Young → “짧은 주기로 빠르게 GC”
    오래된 객체 및 긴 생명의 객체 → Old → “긴 주기로 덜 자주 느리게 GC”
    • Young Generation (= Minor Generation )
      • 새로 객체가 생성되면 여기로 저장됨
      • 짧은 생명주기를 가짐 → GC 대상 1순위
      • GC가 자주 & 빠르게 일어남
      • 내부적으로 Eden, Survivor 로 분리되어있는데 객체가 처음 생성되면 Eden, 여기서 살아남은 객체들이 Survivor로 이동 (잠시 거쳐가는 공간)
    • Old Generation (= Major Generation = Full Generation)
      • Young Generation에서 살아남은 객체가 이쪽으로 이동됨
      • 오래 살아남은 객체가 이쪽으로 이동되므로 메모리 회수빈도가 낮음
      • GC가 낮은 빈도 & 느리게 일어남
  • Memory Fragmentation (메모리 단편화)
    메모리 중간중간을 회수하면 메모리가 띄엄띄엄 공간이 생김. 연속된 공간 확보가 안됨.

    예를 들면
    [O][O][O][O][O][O] → 2번, 5번 메모리 회수할 경우 → [O][ ][O][O][ ][O] → 중간에 빈 공간이 생김

 

  • G1 에서는 옵션을 통해 pause 목표시간을 설정가능함
    -XX:MaxGCPauseMillis=100

 

 

반응형

'JAVA' 카테고리의 다른 글

제어의 역전과 의존성 주입  (2) 2025.07.24
Spring Security 개념 정리  (0) 2025.07.21