Java - 가비지 컬렉션

Java Garbage Collection

Posted by Yan on August 12, 2021

Generation Garbage Collection

가비지 컬렉션이란?

  • 동적으로 할당한 메모리 영역 중 사용하지 않는 영역을 탐지하여 해제하는 기능
  • Java에서 개발자가 프로그램 코드로 메모리를 명시적으로 해제하지 않기 때문에, 메모리 누수 방지를 위해 가비지 컬렉터는 더 이상 필요 없는 객체를 찾아서 지우는 역할을 한다.

동적으로 할당된 메모리 영역 == Heap 모든 Object타입의 데이터 할당 Heap 영역의 Object를 가리키는 참조변수가 Stack에 할당 — 정적으로 할당된 메모리 영역 == Stack 원시 타입의 데이터가 값과 함께 할당 Heap 영역에 생성된 Object 타입의 데이터 참조 값 할당

Garbage Collector의 동작 과정

  1. Garbage Collector가 Stack의 모든 변수를 스캔하면서 각각 어떤 객체를 참조하고 있는지 찾아서 마킹한다. Mark
  2. Reachable Object가 참조하고 있는 객체도 찾아서 마킹한다. Mark
  3. 마킹되지 않은 객체를 Heap에서 제거한다. Sweep

가설(전제조건) Weak generation hypothesis

  • 대부분의 객체는 금방 접근 불가능unreachable 상태가 된다.
  • 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.

이 가설의 장점을 최대한 살리기 위해서

HotSpot VM에서는 물리적 공간을 크게 2개로 나눈다.

  1. Young Generation 영역
    • 새롭게 생성한 객체의 대부분이 위치하는 곳
    • 대부분의 객체가 금방 접근 불가능 상태가 되기 때문에 많은 객체가 Young영역에 생성되었다가 사라진다.
    • 객체가 사라질 때 Minor GC가 발생한다고 말한다.
  2. Old Generation 영역
    • 접근 불가능 상태로 되지 않아 Young영역에서 살아남은 객체가 여기로 복사된다.
    • 대부분 Young영역보다 크게 할당한다. 크기가 큰만큼 Young영역보다 GC가 벅게 발생한다.
    • 객체가 사라질 때 Major GC가 발생한다고 말한다.

  • Permanent Generation 영역은 Method Area라고도 한다.
  • 객체나 억류된 문자열 정보를 저장하는 곳
  • Old영역에서 살아남은 객체가 영원히 남아 있는 곳은 아니다.
  • 이 영역에서 GC가 발생해도 Major GC의 횟수에 포함된다.
Old영역의 객체가 Young영역의 객체를 참조한다면?
  • Old영역에는 512byte의 chunk로 되어있는 card table이 있는데, 카드테이블에는 Old영역 객체가 Young영역 객체를 참조할 때마다 정보가 표시된다.
  • Young영역의 GC를 실행할 때 Old영역에 있는 모든 객체의 참조를 확인하지 않고, 이 카드 테이블만 뒤져서 GC 대상인지 식별한다.
  • 카드테이블은 write barrier를 사용하여 관리한다.

동작 방식

  1. Stop the world
  2. Mark and Sweep

Stop the world

stop-the-world : GC를 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것. - 실행시 쓰레드를 제외한 나머지 쓰레드는 모두 작업을 멈춘다. - GC작업이 끝나면 중단했던 작업을 다시 시작한다. - 모든 GC알고리즘은 stop-the-world를 발생시킨다.

Mark and Sweep

Mark : 사용되는 메모리와 사용되지 않는 메모리를 식별하는 작업
- stop-the-world로 모든 작업을 중단시키면, GC는 스택의 모든 변수나 Reachable 객체를 스캔하면서 각각 어떤 객체를 참고하고 잇는지 탐색한다. 그러면서 사용되고 있는 메모리를 식별하는 과정을 Mark라 한다

Sweep : Mark 단계에서 사용되지 않는다고 분류된 메모리를 해제하는 작업 - Mark가 되지 않은 객체들을 메모리에서 제거하는 과정

Young영역의 구성

  • Young영역은 객체가 제일 먼저 생성되는 곳이다.
  • Eden영역 / Survivor영역(2개)로 이루어진다.

처리 절차

  • Eden : 새로 생성한 대부분의 객체가 생성된 위치
  • Eden에서 GC가 한번 발생한 후 살아남은 객체는 Survivor영역 중 하나로 이동된다
  • Eden에서 GC가 발생하면 이미 살아남은 객체가 존재하는 Survivor영역으로 객체가 계속 쌓인다
  • 하나의 Survivor영역이 가득차게 되면 그 중에서 살아남은 객체는 다른 Survivor영역으로 이동한다. 가득 찬 Survivor영역은 아무 데이터도 없는 상태가 된다.
  • 이 과정을 반복하다가 계속해서 살아남아있는 객체는 Old영역으로 이동한다

  • Survivor영역 중 하나는 반드시 비어있는 상태로 남아있어야 한다.
  • 만약 두 Survivor영역에 모두 데이터가 존재하거나 두 영역 모두 사용량이 0이면 시스템이 정상적인 상황이 아니라고 보면 된다

Garbage Collector 종류

  1. Serial GC
    • GC를 처리하는 스레드가 1개다
    • CPU 코어가 1개만 있을 때 사용하는 방식이다
    • Mark-Compact collection 알고리즘 사용
  2. Parallel GC
    • GC를 처리하는 스레드가 여러 개다
    • Serial GC보다 빠르게 객체를 처리할 수 있다
    • 메모리가 충분하고 코어의 개수가 많을 때 사용하면 좋다
  3. Concurrent Mark Sweep GC (CMS GC)
    • Stop the world를 줄이는 GC
    • stop the world시간이 짧아서, 애플리케이션의 응답 시간이 빨라야 할 때 사용한다
    • 다른 GC방식보다 메모리와 CPU를 더 많이 사용한다
    • Compaction 단계가 제공되지 않는다
  4. G1 GC
    • 각 영역을 Region 영역으로 나눈다
    • GC가 일어날 때 전체영역(Eden, Survival, Old generation)을 탐색하지 않는다
    • 바둑판의 각 영역에 객체를 할당하고 GC를 실행한다
    • 해당 영역이 꽉 차면 다른 빈 영역에 객체를 할당하고 gC를 실행한다
    • STW 시간이 짧다
    • Compaction을 사용한다

reference

Java Garbage Collection [Java] Garbage Collection(가비지 컬렉션)의 개념 및 동작 원리 (1/2) [10분 테코톡] 👌던의 JVM의 Garbage Collector