Python의 메모리 관리는 매우 직관적입니다. 메모리 할당과 해제가 자동으로 처리되기 때문에 개발자가 일일이 신경 쓸 필요가 없습니다. 그리고 이러한 메모리 관리 메커니즘의 핵심에 바로 가비지 컬렉션(Garbage Collection)이 있습니다. 이번 글에서는 Python 가비지 컬렉션의 다양한 측면을 예제와 함께 살펴보겠습니다.
가비지 컬렉션이란 무엇인가?
가비지 컬렉션은 실행 중인 프로그램이 더 이상 사용하지 않는 공유 메모리 영역을 정리하는 프로세스입니다. 가비지 컬렉션을 통해 확보된 메모리는 다른 프로그램이 재사용할 수 있게 됩니다.
Python은 크게 두 가지 방식으로 메모리를 관리합니다.
- 참조 카운팅(Reference Counting)
- 가비지 컬렉션(Garbage Collection)
Python의 가비지 컬렉션은 완전히 자동으로 동작합니다. 반면 C 언어처럼 개발자가 직접 객체를 해제해야 하는 언어도 있습니다. 물론 Python에서도 필요하다면 객체를 수동으로 삭제할 수 있습니다.
>>> x = 9 >>> print(x) 9 >>> del x >>> print(x) Traceback (most recent call last): File "<pyshell#3>", line 1, in <module> print(x) NameError: name 'x' is not defined
위 예제에서는 변수 x를 정의하고 사용한 뒤, 실행 도중 del 키워드로 객체를 삭제한 후(Python에서는 모든 것이 객체입니다) 다시 출력하려고 시도했습니다.
프로그램의 처음 두 줄에서는 객체 x가 유효했지만, 객체 x를 삭제한 이후에는 더 이상 출력할 수 없습니다. 즉, 가비지 컬렉션은 완전히 자동화되어 있으며 개발자가 별도로 신경 쓰지 않아도 된다는 것을 알 수 있습니다.
참조 카운팅(Reference Counting)의 이해
Python의 모든 객체는 앞선 예제의 객체 x처럼 참조 카운트(reference count)와 타입을 가리키는 포인터를 가지고 있습니다. 참조 카운트는 객체가 어떻게 사용되는지에 따라 값이 달라집니다. 예를 들어 객체 x를 다른 객체 y에 할당하면 참조 카운트는 2로 증가합니다.
>>> some_list = [1, 2 ,3, 4, 5, 6, 7, 8, 9] >>> #some_list의 참조 카운트 = 1 >>> other_list = some_list >>> #참조 카운트 = 2 >>> #객체를 인자로 전달해도 참조 카운트는 증가합니다 >>> list_total = sum(some_list) >>> #객체를 리스트에 넣으면 참조 카운트 역시 증가합니다 >>> list_of_list = [some_list, some_list, some_list] >>> >>> #"some_list" 객체의 참조 카운트 확인 >>> import sys >>> sys.getrefcount(some_list) 6
위 예제는 Python 메모리 관리에서 참조 카운팅이 어떻게 동작하는지 보여주는 좋은 사례입니다. 먼저 "some_list" 객체를 생성하면(참조 카운트 = 1), 이를 다른 변수에 할당하고(참조 카운트 = 2), 함수의 인자로 전달하며(참조 카운트 = 3), 이후 같은 객체를 세 번 리스트에 담아 최종적으로(참조 카운트 = 6) "some_list"의 참조 카운트는 6이 됩니다.
>>> import sys >>> sys.getrefcount(some_list) 6 >>> >>> del list_of_list >>> sys.getrefcount(some_list) 3 >>> del some_list >>> sys.getrefcount(some_list) Traceback (most recent call last): File "<pyshell#17>", line 1, in <module> sys.getrefcount(some_list) NameError: name 'some_list' is not defined
del 문으로 list_of_list를 삭제하자 참조 카운트가 3으로 감소했습니다. 마지막으로 some_list 자체를 삭제하면 해당 이름은 더 이상 존재하지 않으므로 NameError가 발생합니다.
이처럼 Python은 참조 카운트가 0이 되는 순간 해당 객체가 차지하던 메모리를 자동으로 회수하며, 이것이 바로 가비지 컬렉션의 기본 원리입니다. 덕분에 개발자는 메모리 누수를 걱정하는 대신 비즈니스 로직 작성에 집중할 수 있습니다.