메모리 관리 : 참조 카운팅과 가비지 컬렉터(GC)의 원리
파이썬은 개발자가 직접 메모리를 수동으로 해제할 필요가 없는 자동 메모리 관리 시스템을 갖추고 있습니다. 이번 글에서는 파이썬이 내부적으로 메모리를 어떻게 관리하고 최적화하는지, 핵심 메커니즘인 참조 카운팅과 세대별 순환 가비지 컬렉터(GC)의 모든 것을 완벽하게 파헤쳐 보겠습니다.
1. 파이썬 메모리 관리와 가비지 컬렉터(GC)란?
파이썬의 가비지 컬렉터(Garbage Collector, GC)는 프로그램 실행 중에 더 이상 사용되지 않는 객체(Garbage)를 자동으로 식별하고 메모리에서 해제하여, 메모리 누수(Memory Leak)를 방지하고 시스템 자원을 효율적으로 관리하는 시스템입니다.
파이썬은 두 가지 주요 메커니즘을 결합하여 가비지 컬렉션을 수행합니다.
-
참조 카운팅 (Reference Counting) (주된 메커니즘)
-
세대별 순환 가비지 컬렉터 (Generational Cycle GC) (보조 메커니즘)
2. 주된 메커니즘: 참조 카운팅 (Reference Counting)
참조 카운팅은 파이썬에서 가장 기본적이고 핵심적인 가비지 컬렉션 방식입니다.
2.1 참조 카운팅의 원리와 장점
모든 파이썬 객체는 자신을 참조하는 변수나 객체의 수를 추적하는 내부 카운터(Reference Count)를 가지고 있습니다.
-
카운트 증가: 객체에 대한 새로운 참조가 생성될 때마다 카운트가
1증가합니다. (예: 변수 할당, 함수 인수로 전달, 컨테이너에 포함 등) -
카운트 감소: 객체에 대한 참조가 사라질 때마다 카운트가
1감소합니다. (예: 변수 삭제, 함수 종료,del키워드 사용 등) -
객체 해제: 객체의 카운트가
0이 되면, 파이썬 인터프리터는 해당 객체가 더 이상 접근 불가능하다고 판단하고 즉시 메모리에서 해제합니다.
참조 카운팅의 장점:
-
즉각적인 해제: 객체가 사용되지 않자마자 바로 메모리에서 해제되므로 메모리 누수를 최소화합니다.
-
간단함: 구현과 이해가 비교적 간단합니다.
2.2 한계점: 순환 참조 (Reference Cycles)
참조 카운팅 방식은 객체들이 서로를 참조하는 순환 참조(Reference Cycles)가 발생할 경우, 각 객체의 카운트가 항상 1 이상으로 유지되어 절대 0이 되지 못하는 치명적인 한계가 있습니다.
# 순환 참조 예시
a = []
b = [a]
a.append(b) # a는 b를 참조, b는 a를 참조. 둘 다 카운트가 1 이상으로 유지됨.
del a, b # 변수는 삭제되지만, 메모리 내의 객체는 해제되지 않음 (참조 카운트가 1 이상으로 남아있음)
3. 보조 메커니즘: 세대별 순환 가비지 컬렉터 (Generational Cycle GC)
참조 카운팅의 한계점인 순환 참조 문제를 해결하기 위해, 파이썬은 gc 모듈을 통해 순환 참조 감지 알고리즘을 주기적으로 실행하는 보조 메커니즘을 사용합니다.
3.1 세대별 GC의 원리와 가설
이 GC는 모든 객체를 세대(Generations)로 나누어 관리합니다. 새로 생성된 객체는 0세대에 속하며, GC 검사에서 살아남은 객체는 다음 세대로 승격됩니다.
-
핵심 가설: “대부분의 객체는 생성된 지 얼마 되지 않아 죽거나(단명), 아주 오랫동안 살아남는 경향이 있다.”
-
효율성: 0세대는 가장 빈번하게 검사하고, 세대가 높아질수록 검사 주기를 길게 가져갑니다. 이는 GC가 매번 모든 객체를 검사하는 비효율을 줄여줍니다.
3.2 순환 참조 감지 과정
-
순환 감지: GC는 객체들 간의 참조 관계를 그래프로 구성하고, 이들 중 외부에서 접근할 수 없는(참조 카운트가 높더라도) 고립된 사이클을 찾아냅니다.
-
해제: 고립된 순환 참조의 일부인 객체들을 가비지로 간주하고 메모리를 안전하게 해제합니다.
3.3 파이썬의 3세대 구조
파이썬의 GC는 기본적으로 세 개의 세대를 가집니다.
| 세대 | 역할 및 대상 | 검사 주기 |
| 0세대 (Gen 0) | 새로 생성된 객체 | 가장 짧음 (가장 자주 검사) |
| 1세대 (Gen 1) | 0세대 검사에서 살아남은 객체 | 0세대보다 길게 검사 |
| 2세대 (Gen 2) | 1세대 검사에서 살아남은 객체 | 가장 길게 검사 |
4. 가비지 컬렉터 수동 제어 (gc 모듈)
파이썬의 가비지 컬렉터는 기본적으로 자동으로 실행되지만, 개발자가 필요에 따라 gc 모듈을 사용하여 수동으로 제어할 수도 있습니다.
import gc
# 수동으로 가비지 컬렉터 실행
gc.collect()