가비지 컬렉션 정리

3 minute read

Naver D2의 글을 보고 정리한 글입니다.


사전 필요 지식:

  • stop-the-world :
    • GC 실행하기 위해 JVM이 애플리케이션을 멈추는 것
    • ‘stop-the-world’발생후
      GC 실행하는 스레드 외의 모든 스레드의 작업은 멈춘다.
  • GC튜닝 :
    • stop-the-world 시간을 줄이는 것

GC는 두가지 전제(가설;weak generational hypothesis)를 토대로 만들어 짐

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

Hot Spot VM에서는 크게

  1. Young영역(Young generation 영역)
    • 새로 생성된 객체들이 있는 공간
    • 대부분 객체는 곧 접금 불가능 상태가 되기 때문에
      Young영역에서 생성되고 사라진다.
    • 여기서 객체가 사라질 때
      Minor GC가 발생한다고 말한다.
  2. Old영역(Old generation 영역)
    • Young영역에서 접근 불가능 상태가 되지 않은 객체가 여기로 복사된다.
    • 대부분 Young영역보다 크게 할당함
    • GC가 적게 발생
    • 여기서 객체가 사라질 때
      Major GC or Full GC가 발생한다고 말함

으로 나뉘었다.

기타 영역

  • Permanent 영역(Permanent generation or Method area)
    • 객체나 억류(?)된 문자열 정보를 저장하는 곳
    • 여기서 GC가 발생하면 Major GC 횟수에 포함됨

Old 영역에 있는 객체가 Young 영역의 객체를 참조하고 있을 경우

  • 카드 테이블
    • Old영역에 512바이트의 덩어리로 된 카드 테이블이 존재
    • Old영역에서 Young영역의 객체를 참조할 때마다 정보가 테이블에 표시됨
    • write barrier를 사용하여 관리
      • Minor GC를 빠르게 할 수 있도록 하는 장치
      • 약간의 오버헤드는 발생하나 전반적인 GC시간 감소

Young영역

Young영역의 구성

  • Eden영역
  • survivor영역(2개)
  • 총 3개 영역

처리 절차

  • 새로 생성한 대부분의 객체는 Eden영역에 위치함
  • Eden 영역에서 GC가 한 번 발생한 후
    살아남은 객체는 survivor영역 중 하나로 이동
  • Eden영역에서 GC발생하면 계속 survivor영역에 객체가 쌓임.
  • 하나의 survivor영역이 가득 차게 되면
    그 중 살아남은 객체를 다른 survivor영역으로 이동
    그리고 그 가득찬 survivor영역은 리셋됨.
  • 이 과정을 반복하며
    계속 살아남아 있는 객체는 Old영역으로 이동
    • survivor영역 중 한 곳은 반드시 상태로 있어야 함.
    • 만약 servivor두 영역에 모두 데이터가 있거나
      모두 사용량이 0이면
      그 시스템은 정상적인 상황이 아닌것

참고
HotSpot VM은 빠른 메모리 할당을 위해 아래의 기술을 사용

  1. bump-the-pointer
    • Eden영역에 할당된 마지막 객체(맨 위에 있는)를 추적
    • 생성되는 객체의 크기가 Eden영역에 넣기에 적당한지 확인
    • 만약 적당하다면 Eden영역에 넣고 그 객체가 마지막 객체가 됨(맨 위에 있게 됨)
    • 새로 추가된 객체만 검사하면 되므로 메모리 할당이 빠름
    • bump-the-pointer이 멀티스레드 환경에서 lock이 발생하는 문제가 있음
      • 이를 보완하기 위해 이 TLABs필요.
  2. TLABs(Thread-Local Allocation Buffers)
    • 각각 스레드가 각자의 몫에 해당하는 Eden영역의 작은 부분을 가질수 있도록 함
    • 각 스레드는 자기 몫의 TLABs만 접근할 수 있서
      bump-the-pointer 기술 사용해도 아무런 락 없이 메모리 할당 가능

중요 포인트

  • Eden영역에 최초로 객체가 만들어지고
    servivor영역을 통해 Old영역으로 오래 살아남은 객체가 이동한다

Old영역

Old영역은 기본적으로 데이터가 가득차면 GC 실행.

  • 기본적인 GC 방식 5가지(jdk 7 기준)
    • Serial GC
    • Parallel GC
    • Parallel Old GC(Parallel Compacting GC)
    • Concurrent Mark & Sweep GC(CMS)
    • G1 GC(Garbage First GC)

이 중 운영 서버에서 절대 사용하면 안되는 방식은 Serial GC다.

  • Serial GC는 CPU 코어가 하나만 있을 때 사용하기 위해 만든 방식
  • Serial GC는 애플리케이션의 성능을 떨어뜨림

alt

  • 각 GC의 대략적인 절차
  • 그림 출처 : https://www.dhaval-shah.com/images/wp-content/uploads/2019/11/types-of-gc.png __

Serial GC (-XX:+UseSerialGC)

  • Young영역에서의 GC는 위의 설명한 방식과 같음(처리 절차)
  • Old영역의 GC는 mark-sweep-compact라는 알고리즘을 사용
    1. Old영역에 살아 있는 객체 실별(mark)
    2. 힙(heap)의 앞 부분부터 확인하여 살아 있는 것만 남김(sweep)
    3. 각 객체들이 연속되게 쌓이도록 힙의 가장 앞 부분부터 채움
      • 객체가 있는 부분과 없는 부분으로 나뉨(compact)
  • 적은 메모리, cpu 코어 갯수가 적을 때 적합


Parallel GC (-XX:+UseParallelGC)

  • 기본적인 알고리즘은 Serial GC와 같음
    그러나 Serail GC는 스레드가 하나이고 Parallel GC는 여러개
  • 그래서 Serial GC보다 빠르게 처리
  • 많은 메모리, cpu 코어 갯수가 많을 때 적합
  • Throughput GC라고도 함


Parallel Old GC(-XX:+UseParallelOldGC)

  • Parallel GC방식의 Old영역 GC 알고리즘만 다름
  • Mark-Summary-Compaction 단계를 거침.
    • summary 단계는 앞서 GC를 수행한 영역에 대해
      별도로 살아 있는 객체를 식별
    • mark-sweep-compaction알고리즘의 sweep단계와 다르고
      더 복잡한 단계를 거침


Deprecated in Java 9 and Removed Java 14 CMS GC (-XX:+UseConcMarkSweepGC)

  • 초기 Initial Mark 단계
    • 클래스 로더에서 가장 가까운 객체 중
      살아 있는 객체 찾음
  • Concurrent Mark 단계에서는
    Initial Mark에서 살아 있는 객체들을 따라가면서 확인
  • 다른 스레드가 실행 중인 상태에서 동시에 진행
  • remark 단계
    • Concurrent Mark 단계에서
      새로 추가되거나 참조가 끊긴 객체를 확인
  • Concurrent sweep단계
    • 쓰레기를 정리하는 작업 실행
      (다른 스레드가 실행되고 있는 상황에서)
  • Low Latency GC라고도 부름
  • 응답속도가 중요할 때 사용
  • 장점
    • stop-the-world 시간이 짧음
  • 단점
    • 다른 GC보다 메모리, CPU를 많이 사용
    • Compaction단계가 기본적으로 제공되지 않음
  • 사용 전 신중하게 검토후 사용 필요
  • 조각난 메모리가 많아 Compaction작업을 실행하면
    다른 GC방식의 stop-the-world 시간보다 더 길기에
    Compaction 작업이 얼마나 자주, 오랫동안 수행하는지 확인!!



alt

  • G1 GC시간
  • 그림 출처 : https://docs.oracle.com/javase/9/gctuning/img/jsgct_dt_004grbg_frst_hp.png __ G1 GC
  • 바둑판 영역에 객채를 할당 및 GC 실행
  • 해당영역이 꽉 차면 다른 영역에 객체를 할당하고 GC실행
  • 위의 Young->Old영역 하는 절차가 빠짐
  • CMS GC를 대체하기 위해 만들어짐
  • 성능이 제일 좋음


각 서비스마다 GC옵션을 잘 따져봐야한다.A 서비스에서 최적의 옵션이 B 서비스에서는 전혀 다를 수 있다고 한다.

Tags: ,

Categories:

Updated:

Leave a comment