잠깐만요
레퍼런스 카운트란?
메모리 영역 중에 힙(heap)이라는 공간이 있습니다(9장 참조). C/C++에서는 힙에 할당한 메모리는 프로그래머가 직접 해제해야 합니다. 하지만 자바, C#, 파이썬 등에서는 메모리를 프로그래머가 직접 관리하지 않고 해당 언어가 스스로 해제합니다. 더는 사용하지 않는 메모리를 언어 차원에서 해제한다는 개념을 가비지 컬렉션(garbage collection)이라고 합니다.
그렇다면 프로그래밍 언어는 가비지 컬렉션을 어떻게 구현할까요? 가장 단순한 형태인 Mark and Sweep부터 가장 빠르다고 알려진 Stop and Copy, Reference Counting 등 가비지 컬렉션을 구현하는 알고리즘에는 여러 가지가 있습니다.
파이썬은 레퍼런스 카운팅으로 가비지 컬렉션을 구현합니다. 여기서 레퍼런스는 참조(reference) 즉, 무엇인가를 가리킨다는 의미입니다. 파이썬에서 변수는 값을 직접 갖는 게 아니라 상수 객체를 가리키고 있다고 했는데, 이러한 개념이 바로 참조입니다.
예를 들어 변수 a가 10이라는 상수 객체를 가리킨다고 가정합시다. 가리키는 대상의 개수인 레퍼런스 카운트는 1입니다. 이때 b = a라는 코드를 입력하면 변수 b도 10이라는 상수 객체를 가리키게 됩니다. 그러면 상수 객체 10의 레퍼런스 카운트는 2가 됩니다.
a와 b가 10이 아닌 서로 다른 객체를 가리키도록 코드를 수정하면, 상수 객체 10은 레퍼런스 카운트가 0이 되고 메모리에서 해제됩니다. 더 이상 10을 가리키는 객체가 없어졌기 때문입니다. 파이썬으로 레퍼런스 카운트를 직접 확인해 보겠습니다.
>>> import sys
>>> a = "abcde"
>>> sys.getrefcount(a)
2
sys 모듈을 임포트하고 변수 a가 문자열 상수 abcde를 참조하게 합니다. 그리고 sys 모듈의 getrefcount( ) 함수를 호출하여 레퍼런스 카운트를 확인합니다. 그런데 결과가 조금 이상합니다. 1이 나올 줄 알았는데 2가 나왔습니다. getrefcount( ) 함수가 실행되면서 “abcde”라는 문자열 상수를 참조하기 때문입니다. 실행이 완료되면 함수 실행에 의한 레퍼런스 카운트는 사라지므로 실제 레퍼런스 카운트는 출력 값에서 1을 빼면 됩니다.
>>> b = a
>>> sys.getrefcount(a)
3
b라는 변수도 문자열 abcde를 가리키므로 레퍼런스 카운트가 3으로 늘어난 것을 알 수 있습니다.