파이썬
가비지 컬렉션(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에 반환