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이 너무작을경우 미사용 권장)
참고 자료
답글 남기기