파이썬

가비지 컬렉션(garbage collection, gc)

그레고리력 2021. 7. 1. 19:10

GC


  • 힙 영역(동적 메모리 할당)에서 사용하지 않는 객체를 삭제하는 프로세스
  • garbage collection(가비지 컬렉션)과 reference counting(레퍼런스 카운팅)을 통해 할당 된 메모리를 관리

레퍼런스 카운팅

  • 모든 객체는 참조당할 때 레퍼런스 카운터를 증가시키고 참조가 없어질 때 카운터를 감소시킴
  • 즉 해당 객체에 접근할 수 있는 방법의 수
  • 이 카운터가 0 이 되면 객체가 메모리에서 해제(참조되지 않는 객체들 - unreachable)
  • 순환참조 문제가 발생함

Mark and Sweep

  • 자바와 자바스크립트, 순환참조 문제 해결
  • 레퍼런스 카운트가 0이되면 제거하는 방식과 달리 의도적으로 gc를 실행해주어야 함, 어플리케이션과 gc실행이 병행됨
  • 루트부터 그래프 순환을 통해 연결된 객체를 찾아내(Mark), 연결이 끊어진 객체를 제거(Sweep)
  • 닿을 수 있는지(reachable)를 판단

Stop the world, 자바

  • gc를 실행하기위해 어플리케이션의 실행을 멈추는 것
  • Serial gc : 싱글스레드 환경 및 힙 영역이 작을 때, stop the world 시간이 김
  • parallel gc
  • CMS gc : stop the world 시간을 최소화하기 위해 고안
  • g1 gc

가비지 컬렉터

  • 현대적인 언어는 자동 메모리 관리를 함, C언어의 malloc과 같은 문제에서 출발(메모리 해제해주어야 하고 사용중인 메모리 해제했을 때 문제)
  • 파이썬의 gc 모듈을 통해 가비지 컬렉터를 제어할 수 있는데 gc 모듈은 reference cycles(순환 참조)문제를 해결할 수 있음
  • 가비지 컬렉터는 내부적으로 generation(세대)과 threshold(임계값)로 가비지 컬렉션 주기와 객체를 관리
  • 세대는 0 세대, 1 세대, 2 세대로 구분되는데 최근에 생성된 객체는 0 세대(young)에 들어가고 오래된 객체일수록 2 세대(old)에 존재
  • 가비지 컬렉터는 0 세대일수록 더 자주 가비지 컬렉션을 하도록 설계
  • 새로운 객체는 1세대 가비지컬렉터에서 life(수명)를 시작해 객체가 살아남으면, 두 번째 세대로 올라감
  • 각 세대마다 가비지 컬렉터 모듈에는 임계값이 있어 객체 수가 해당 임계값을 초과하면 가비지 콜렉션이 콜렉션 프로세스를 시작함

Generational Hypothesis

  • 가비지 콜렉션은 Generational Hypothesis라는 가설을 기반으로 작동합니다. 이 가설은 ‘대부분의 객체는 생성되고 오래 살아남지 못하고 곧바로 버려지는 것’과 ‘젊은 객체가 오래된 객체를 참조하는 상황은 드물다’는 2가지 가설입니다.

장점


  • 메모리 누수 방지
  • 해제된 메모리에 접근하거나 이미 해제된 메모리 다시 해제하는 경우 방지

단점


  • 큰 규모의 메모리 할당이 발생, 필요한 메모리도 수거하고 재할당하는 일이 발생
  • 요소들의 대부분은 닿을 수 없음(unreachable)의 상태로 표시됨 (필요없는메모리소모)
  • 어떤 메모리를 해제할지 결정하는 데 비용이 든다. gc 알고리즘이 메모리 해제 시점을 추적해야 해서 오버헤드 발생
  • gc 타이밍이나 점유 시간을 미리 예측하기 어려워 프로그램이 예측 불가능하게 일시적으로 정지할 수 있음

js gc


  • 마크스위프 알고리즘
  • 루트(Roots) : 코드에서 참조되는 전역변수, 자바스크립트에서 루트로 동작할 수 있는 전역변수는 window 객체, nodejs에서는 global, 가비지 컬렉터는 모든 루트의 완전한 목록을 만듦
  • 활성상태표시(active) : 모든 루트와 그 자식들을 검사해 활성화 여부를 표시, 루트가 닿을 수 없는 것들도 가비지로 표시
  • 메모리 반환 : 마지막으로 가비지 컬렉터는 활성으로 표시되지 않은 모든 메모리를 OS에 반환