Python에서 메모리 관리는 어떻게 될까?
C언어는 수동으로 메모리를 관리한다 (malloc, calloc etc...)
Java는 Garbage Collection 기능이 존재한다.
Python 또한 Java처럼 Garbage Collection 기능이 있다.
그리고 Python GC에 대한 가장 일반적인 정보는 아래와 같다.
주요한 GC 기법이다.
Python에서 객체를 만들 때, Python 타입과 reference count가 생성된다.
reference count는 객체가 참조될 때마다 증가하고, 객체 참조가 해제될 때마다 감소한다.
reference count가 증가하는 방식은 크게
1. 변수에 객체 할당
2. data structure에 객체를 추가 - e.g list에 추가하거나 instance 속성으로 추가
3. 함수의 인자로 객체 전달.
reference count가 주로 사용되는 기법이라면, generational garbage collection은 보조로 사용되는 기법이다.
reference count 기법으로 "쓰레기" 객체를 처리할 수 없는 경우가 있기 때문이다. 이런 문제를 reference cycle이라고 한다.
객체가 자기 자신을 가리키는 경우다.
예를 들어, 아래처럼 배열이나 객체에 자기 자신을 추가하는 상황이다.
>>> a = list()
>>> a.append(a)
>>> del a
이런 경우 참조 횟수가 아직 0이 아니지만 객체에 접근할 수 없고, 참조 횟수를 더이상 줄일 수 없게 되어 reference count로 처리할 수 없다.
class MyClass:
def __init__(self):
self.x = None
a = MyClass() # a의 메모리를 0x01
b = MyClass() # b의 메모리를 0x02 라고 가정하자.
a.x = b
b.x = a
# 0x01은 a와 b.x가 가리키고 있고
# 0x02는 b와 a.x가 가리키고 있다.
# 그러므로 둘 다 reference count = 2
del a
del b
이렇게 서로가 서로를 참조하고 있으면 마지막 del
로 인해 참조가 1씩 줄어들어 1이 되지만 더이상 참조할 수 없기 때문에 처리할 수 없다.
garbage collector가 메모리의 모든 객체를 추적한다.
이 때, 객체들은 세대generation로 분류된다. 새로 만들어진 객체는 가장 어린young 0세대이다.
이런 세대는 0세대부터 2세대까지 있고 0세대가 가장 어린 세대로 2세대가 가장 오래된 세대다.
garbage collector가 garbage collect process를 실행하고, 여기서 살아남은 객체는 이전 세대, 즉 오래된 세대로 옮겨진다.
garbage collect process는 세대마다 정해진 임계값threshold에 따라 실행 주기가 설정된다.
객체의 수가 threshold보다 커지면 process가 실행됩니다.
어린 세대일수록 garbage collection이 더 자주 발생합니다.
위 대답1에서 빼먹은 설명이 하나있다.
위 내용은 모두 CPython 인터프리터에서 해당되는 내용이다.
인터프리터의 종류에 따라 사용하는 GC 기법이 다를 수 있다.
Java로 작성된 Python 인터프리터인 Jython에는 CPython과 유사하게 reference counting과 collector 기능이 있다.
Rust로 작성된 RustPython에는 reference counting 기능이 존재한다.
추가적인 기능이 있을 것으로 예상되지만 아직 찾진 못했습니다...
Python으로 작성된 Python 인터프리터인 PyPy를 구현하기 위해 개발된 RPython에는 무려 6가지 GC 기능을 제공한다.
"Python GC는 reference counting과 generational garbage collection 기능이 있다." 는 반쪽짜리 대답인 셈.
정확히는 "CPython의 GC는..." 이라고 해야한다.
RPython에서 제공하는 GC 기능에 대해서는 차후에 다루어보도록 하겠다...
https://medium.com/dmsfordsm/garbage-collection-in-python-777916fd3189