가비지 컬렉션(GC)

최권민·2023년 6월 25일
0

CS스터디

목록 보기
3/8

가비지 컬렉션(GC)

  • 가비지 컬렉션은 자바의 메모리 관리 방법 중의 하나로 JVM의 Heap 영역에서 동적으로 할당했던 메모리 중 필요 없게 된 메모리 객체를 모아 주기적으로 제거하는 프로세스를 말함

  • 과거 C / C++ 언어에서는 가비지 컬렉션이 없어 프로그래머가 수동으로 메모리 할당과 해제를 일일이 해줘야 했었음

  • 반면 Java, 파이썬, 자바스크립트, Go 언어 등 많은 언어에서는 가비지 컬렉터가 메모리 관리를 대행해 주기 때문에 한정된 메모리를 효율적으로 사용할 수 있게 하고, 개발자 입장에서 메모리 관리, 메모리 누수 문제에 대해 관리하지 않아도 되어 오롯이 개발에만 집중할 수 있다는 장점이 있음

  • 그러나 자동으로 처리해준다 해도 메모리가 언제 해제되는지 정확하게 알 수 없어 제어하기 힘들며, 가비지 컬렉션이 동작하는 동안에는 다른 동작을 멈추기 때문에 오버헤드가 발생되는 문제점이 있음

    • 이렇게 GC때문에 동작이 멈추는 것을 Stop-The-World(STW)라고 한다.
    • 이로 인해 GC가 너무 자주 실행되면 소프트웨어 성능 하락의 문제가 되기도 함
    • 이런 특성에 따라 실시간성이 매우 강조되는 프로그램일 경우 GC에게 메모리를 맡기는 것은 맞지 않을 수 있음
    • 어플리케이션의 사용성을 유지하면서 효율적이게 GC를 실행하는 최적화 작업이 개발자의 숙제가 됨
  • GC는 특정 개체에 유효한 레퍼런스가 있는지 유무에 따라 Reachable 과 Unreachable로 구분한다.

    • Reachable : 객체가 참조되고 있는 상태
    • Unreachable : 객체가 참조되고 있지 않은 상태 (GC의 대상이 됨)
  • 어디서든 참조하고 있지 않은 객체(Unreachable)들을 주기적으로 GC가 제거해 준다.

  • GC는 3가지 단계로 객체를 솎아낸다. (Mark, Sweep, Compaction)

    • Mark에서는 현재 이어져 있는(사용하고 있는) 객체와 그렇지 않은 객체를 구분한다.
    • Sweep에서는 위에서 찾은 이어지지 않은 객체를 heap에서 제거한다.
    • Compaction 에서는 Sweep 후 분산된 객체들을 시작 주소로 모아 메모리가 할당된 부분과 그렇지 않은 부분으로 압축한다.
  • JVM의 힙(heap) 영역은 동적으로 레퍼런스 데이터가 저장되는 공간으로서, 가비지 컬렉션의 대상이 되는 공간이다.

  • Heap 영역은 처음 설계될 때 다음의 2가지를 전제로 설계되었다.

    • 대부분의 객체는 금방 접근 불가능한 상태가 된다.
    • 오래된 객체에서 새로운 객체로의 참조는 아주 적게 존재한다.
  • 즉, 객체는 대부분 일회성이며 메모리에 오래 남아있는 경우는 드물다는 것이다.

  • 그렇기에 Heap을 새로운 객체들이 할당되는 영역과 오랫동안 살아남은 객체들이 존재하는 영역으로 나누어 관리한다.

    • Young Generation
    • Old Generation
  • Young 영역(Young Generation)

    • 새롭게 생성된 객체가 할당(Allocation)되는 영역
    • 대부분의 객체가 금방 Unreachable 상태가 되기 때문에, 많은 객체가 Young 영역에 생성되었다가 사라짐
    • Young 영역에 대한 가비지 컬렉션을 Minor GC라고 부름
  • Old 영역(Old Generation)

    • Young 영역에서 Reachable 상태를 유지하여 살아남은 객체가 복사되는 영역
    • Young 영역에서 크게 할당되며, 영역의 크기가 큰 만큼 가비지는 적게 발생한다.
    • Old 영역에 대한 GC를 Major GC 또는 Full GC라고 부름
  • Young 영역은 Eden, survivor 0, survivor 1 으로 나뉨

    • Eden은 new를 통해 새로 생성된 객체가 위치
    • GC 이후 살아남은 객체는 Survivor 영역으로 이동
  • Survivor 영역

    • 최소 1번의 GC 이상 살아남은 객체가 존재하는 영역
    • 둘 중 하나의 Survivor 영역은 비어 있어야 함 (서로 스위치되면서 객체가 들어감)
  • Young Generation 공간은 Old Generation 공간에 비해 상대적으로 작기 때문에 메모리 상의 객체를 찾아 제거하는 데 적은 시간이 걸림

    => Young Generation 영역에서 발생되는 GC를 Minor GC라 부름

  • Major GC
    • Young Generation에서 GC과정 중 제거되지 않은 경우 age 임계값이 차게 되어 이동된 객체의 모음
    • 객체들이 계속 Promotion 되어 Old 영역의 메모리가 부족해지면 Major GC가 발생
  • Old Generation은 Young Generation에 비해 상대적으로 큰 공간을 가지고 있어, 이 공간에서 메모리 상의 객체 제거에 많은 시간이 걸림
  • Young 영역은 일반적으로 GC가 보통 0.5초에서 1초 사이에 끝남
  • Old 영역의 Major GC는 일반적으로 10배 이상의 시간이 사용
  • 앞에서 나온 Stop-The-World 문제가 발생하게 됨
    • Major GC가 일어나면 CPU에 주는 부하가 커지고 멈추거나 버벅이는 현상이 일어남
    • 따라서 GC의 알고리즘이 중요함

JAVA에서의 GC


  • 자바 8에서는 Parallel GC 사용
  • Minor GC에는 Mark-Sweep을 사용하고 Major GC에는 Mark-Sweep-Conpact를 사용
  • Young 영역의 Minor GC를 멀티 쓰레드로 수행됨
    • Old 영역은 여전히 싱글 쓰레드
  • 자바 9+ 버전에서는 G1 GC(Garbage First) 사용
    • 4GB 이상의 힙 메모리 권장
    • 기존 GC에서는 Heap 영역을 Young / Old 영역으로 나누어 사용
    • G1 gc는 이러한 개념을 뒤엎는 Region이라는 개념을 새로 도입하여 사용
    • 전체 Heap 영역을 Region이라는 영역으로 체스판과 같이 분할하여 상황에 따라 Eden, Survivor, Old 등 역할을 고정이 아닌 동적으로 부여
    • Garbage로 가득찬 영역을 빠르게 회수하여 빈 공간을 확보하므로, 결국 GC 빈도가 줄어드는 효과
      • 일일히 메모리를 탐색해 객체들을 제거하는 대신 메모리가 많이 차 있는 영역을 우선적으로 GC
profile
하나의 궤적을 따라서

0개의 댓글