틀린 부분이 있다면 댓글로 알려주신다면 감사하겠습니다.
앞서 참조 카운팅과 그로 인해 발생할 수 있는 순환 참조를 해결하기 위해 파이썬에서는 GC(Garbage Collector)라는 가비지 컬렉터를 사용합니다.
C 언어에서는 메모리를 직접 할당하고 해제해야 합니다. 하지만 파이썬에서는 가비지 컬렉터(Garbage Collector)를 통해 자동으로 메모리를 관리해줍니다. 이로 인해 수동으로 메모리를 할당하고 해제해야 하는 번거로움이 사라지며, 메모리 누수도 자동으로 방지할 수 있습니다. 가비지 컬렉터는 다른 언어에서도 메모리 관리를 위해 존재합니다. 더 궁금하신 점이 있다면 아래 링크를 참고해보셔도 좋을 것 같습니다.
https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals#benefits
아무튼 가비지 컬렉터의 가장 큰 이유는 메모리 관리에 있습니다. 부수적인 이유로는 이를 통해 생산성이 향상된다는 점 등을 들 수 있습니다.
가비지 콜렉터에 대한 글을 찾던 중, 왜 사용하는지에 대한 이유를 참고할 수 있는 글을 발견했습니다. 아래 링크를 참고해보시면 도움이 될 것입니다.
https://stackoverflow.com/questions/61999527/why-is-garbage-collection-necessary
위의 내용을 조금만 보면 유추할 수 있습니다. 가비지 컬렉터는 메모리 관리를 해주는 역할을 합니다. 좀 더 구체적으로 말하자면, 프로그래밍 언어에서 사용되지 않는 객체를 자동으로 찾아내어 메모리를 해제해주는 메모리 관리 시스템이라고 설명할 수 있습니다.
https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)
지금부터 설명하는 내용은 Python 문서(Python Docs)의 글을 정리하기 위해 작성한 것입니다.
https://devguide.python.org/internals/garbage-collector/index.html#identifying-reference-cycles
전 글에서 우리는 파이썬 객체가 아래와 같이 구성이 되어있다고 했습니다.
object -----> +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ \
| ob_refcnt (참조 카운트) | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | PyObject_HEAD
| *ob_type (객체의 타입 정보) | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ /
| ... (기타 데이터) |
하지만 파이썬 가비지 컬렉터에 대한 정보도 포함합니다.
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ \
| *_gc_next (다음 객체를 가리키는 포인터) | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | PyGC_Head
| *_gc_prev (이전 객체를 가리키는 포인터) | |
object -----> +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ /
| ob_refcnt (참조 카운트) | \
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | PyObject_HEAD
| *ob_type (객체의 타입 정보) | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ /
| ... (기타 데이터) |
typedef struct {
PyGC_Head gc; // 가비지 컬렉션 정보를 저장하는 필드
PyObject obj; // 실제 파이썬 객체
} PyGCObject;
#ifndef Py_LIMITED_API
typedef union _gc_head {
struct {
union _gc_head *gc_next;
union _gc_head *gc_prev;
Py_ssize_t gc_refs;
} gc;
double dummy; /* force worst-case alignment */
} PyGC_Head;
여기서 추가된 것들이 있는데 바로 PyGC_Head의 _gc_next와 _gc_prev입니다. 이들은 이중 연결 리스트를 구성하여, GC가 객체들을 추적하고 정리하는 데 사용됩니다. (이중 연결 리스트는 객체 간 삭제, 이동, 추가가 용이하기 때문에 선택되었습니다.)
(이떄 추적하고 정리할 때는 C API로 처리가 됩니다.)
가비지 컬렉터도 항상 장점만 존재하는 것은 아닙니다. 다음과 같은 단점이 있습니다:
가비지 컬렉터의 변경 사례도 있습니다. Instagram을 개발할 때는 Python 프레임워크인 Django를 사용했습니다. 이때 성능 문제를 해결하기 위해 가비지 컬렉터 설정을 변경한 적이 있습니다. 궁금하시다면 아래 링크를 참고하시면 좋을 것 같습니다.
https://instagram-engineering.com/dismissing-python-garbage-collection-at-instagram-4dca40b29172
(그 결과 마개조한 파이썬이 개발됐습니다.)
https://github.com/facebookincubator/cinder