GC(Garbage Collector) 알아보기

GC(Garbage Collector)

GC란 자바 애플리케이션에서 사용하지 않는 메모리를 자동으로 수거하는 기능을 말한다.

C/C++ 같은 언어는 메모리를 할당하고 직접 해제해야했지만,

자바에서는 GC를 이용하여 개발자들이 메모리 관리를 비교적 신경쓰지 않아도 된다.

GC가 필요한 이유?

프로그램이 동적으로 할당했던 메모리 영역(= Heap Area) 중 필요 없게된 영역(= 어떤 변수도 가르키지 않음)을 알아서 해제해준다.

장점

  • 메모리 누수를 막아준다.
  • 해제된 메모리 접근을 막아준다.
  • 해제한 메모리를 또 해제하는 것을 막아준다.

→ 개발자의 실수를 막아줌

단점

  • GC 작업 자체는 순수 오버헤드가 발생함
  • 개발자는 GC가 언제 메모리를 해제하는지 모름

→ 실시간성이 매우 강조되는 프로그램일 경우 GC에게 메모리 관리를 맡기는 것이 알맞지 않을 수 있음

GC를 구현하는 대표적인 알고리즘 2가지

Reference Counting

  • 객체가 생성되면 해당 객체의 Reference Count가 1로 초기화됩니다.
  • 다른 객체가 이 객체를 참조할 때마다 Reference Count가 1씩 증가합니다.
  • 객체를 참조하던 포인터가 다른 객체를 가리키거나 사라지면 Reference Count는 1씩 감소합니다.
  • Reference Count가 0이 되는 순간, 해당 객체는 더 이상 참조되지 않으므로 메모리에서 해제(GC)됩니다.

→ 순환 참조라는 문제가 있음(만약 사용하지 않는 객체지만 서로가 서로를 참조하고 있다면 0이 되지 않음)

Mark And Sweep(Java or js 가 사용하는 알고리즘)

가비지 컬렉션이 될 대상 객체를 식별(Mark)하고, 이를 제거(Sweep)한 후, 파편화된 메모리 영역을 정리하는 작업(Compaction)을 수행합니다.

  • Mark 과정:
    • 가비지 컬렉터는 Root Space에서 시작하여 그래프 순회를 통해 접근 가능한 객체들을 찾아냅니다.
    • 이 과정에서 각 객체가 어떤 객체를 참조하고 있는지를 추적하며, 접근 가능한 객체들을 ‘마킹’합니다.
    • 마킹된 객체는 현재 참조되고 있어 메모리에서 유지해야 하는 객체들입니다.
  • Sweep 과정:
    • 마킹되지 않은 객체, 즉 더 이상 참조되지 않는 Unreachable 객체들을 Heap에서 제거합니다.
    • 이 과정은 메모리에서 불필요한 객체들을 해제하여 사용 가능한 메모리를 확보합니다.
  • Compaction 과정:
    • Sweep 과정 이후, 메모리에 분산된 객체들이 남아 있을 수 있습니다. Compaction은 이러한 객체들을 Heap의 시작 주소로 모아 메모리를 정리하는 과정입니다.
    • 이를 통해 메모리가 할당된 부분과 그렇지 않은 부분을 구분하여 메모리 단편화(Memory Fragmentation)를 줄일 수 있습니다.
    • (일부 가비지 컬렉터는 Compaction 단계를 생략하기도 합니다.)

Mark And Sweep의 단점이자 특징

  • 의도적으로 GC를 실행시켜야 한다.
  • 어플리케이 실행과 GC 실행이 병행된다 .

GC의 동작과정

JVM의 Heap 영역은 크게 두 영역, Young Generation, Old Generation으로 나뉜다.

Young Generation에서 발생하는 GC는 minor gc, Old Generation에서 발생하는 GC는 major gc라고 불린다.

이때 Young Generation은 또 다시 Eden, Survivor 0, Survivor 1 영역으로 나뉜다.

Eden 은 새롭게 생성된 객체들이 할당되는 영역,

Survivor 영역은 minor gc로 부터 살아남은 객체들이 존재하는 영역이다.

이때 Survivor 영역은 0과 1 둘중 하나는 꼭 비어 있어야 한다는 특징이 있다.

객체가 생성 되다가 Eden 영역이 꽉 차는 순간 minor gc가 일어난다.

이때 앞에서 공부한 Mark And Sweep이 일어나는데, 루트로 부터 Reachable이라 판단된 객체는 age-bit를 증가시켜 Survivor 영역으로 옮겨진다.

(이때 지정한 age-bit가 넘을 시 Old 영역으로 옮겨진다. 이것을 promotion 이라고 함)

시간이 흘러 Old generation이 가득차게 될 경우 major gc가 발생한다.

Major GC가 발생할 경우 Stop The World가 발생하며, GC를 제외한 모든 애플리케이션 스레드가 일시적으로 멈춥니다.

GC의 종류

GC 알고리즘은 다양하게 존재하고, 각 서비스나 상황에 맞춰 쓰는 것이 중요하다고 한다.

Serial GC

  • 하나의 쓰레드로 GC를 실행한다.
  • Stop The World 시간이 길다.
  • 싱글 쓰레드 환경 및 Heap이 매우 작을때 사용됨
  • 보통 실무에서 사용하는 경우는 없다 (디바이스 성능이 안좋아서 CPU 코어가 1개인 경우에만 사용)

Parallel GC

  • 여러 개의 쓰레드로 GC를 실행한다.
  • 멀티코어 환경에서 사용한다.
  • Java 8의 default GC 방식

CMS GC(Concurrent Mark Sweep)

  • Stop The World를 최소화 하기 위해 고안됨
  • GC 작업을 어플리케이션과 동시에 실행한다.
  • 아래에 나오는 G1 GC 등장에 따라 Deprecated 됨

G1 GC(Garbage First)

  • Heap 영역을 일정 크기의 Region으로 나누어 사용됨 → 런타임에 G1 GC가 필요에 따라 영역별 Region의 개수를 튜닝함
  • Java 9 부터 default GC 방식
  • 4GB 이상의 힙 메모리, Stop the World 시간이 0.5초 정도 필요한 상황에 사용 (Heap이 너무작을경우 미사용 권장)

참고 자료

https://d2.naver.com/helloworld/1329


답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

Captcha loading…