Memory allocation(1) Reference counting

1 분 소요


Python은 C, C++과 같이 프로그래머가 직접 malloc(), calloc()과 같은 함수를 사용하여 메모리를 할당해주거나 해제해줄 필요가 없습니다. 파이썬은 reference counting과 garbage collection을 사용하여 자동으로 메모리 할당/해제를 처리합니다.

Reference counting

Reference counting은 말 그대로 어떤 객체가 다른 객체로부터 참조된 횟수를 세는 방식을 사용합니다. sys 모듈의 getrefcount()를 사용하면 객체의 참조된 횟수를 구할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import sys


class Python():
  def __init__(self):
    ...

if __name__ == "__main__":
  obj = Python()
  print(sys.getrefcount(obj))  # 2
  obj2 = obj
  print(sys.getrefcount(obj))  # 3
  obj3 = obj
  print(sys.getrefcount(obj))  # 4
  obj2 = 'obj2'
  print(sys.getrefcount(obj))  # 3
  obj3 = 'obj3'
  print(sys.getrefcount(obj))  # 2

예상한 결과에 +1이 된 값이 출력됨을 확인할 수 있습니다. 이는 getrefcount()로 obj가 인자로 넘겨질 때 임시로 참조되기 때문입니다.

위 예제와 같이 reference count는 obj가 참조될 때마다 1 증가하고 참조가 해제될 때마다 1 감소하는 것을 확인 할 수 있습니다. Reference count가 0이 되면 obj의 메모리 할당이 해제됩니다.

Reference count는 매우 효과적이지만, 몇가지 경우는 정상적으로 메모리 해제를 하지 못합니다. 대표적인 경우로는 reference cycle이 일어나는 경우입니다. Reference cycle은 한개, 혹은 그 이상의 객체들이 서로를 참조하고 있는 상태를 말합니다.

1
2
3
4
5
6
7
8
9
10
# 예시 1
a.attr = b
b.attr = a

# 예시 2
def make_cycle():
  L = []
  L.append(L)

make_cycle()

첫번째 예시와 같이 두 객체의 속성이 각각 상대 객체를 참조하고 있는 경우가 대표적인 reference cycle의 예시라고 볼 수 있습니다.

두번째 예시를 보면 make_cycle() 함수가 종료되면 L의 메모리는 해제되어야 하지만 L은 내부적으로 reference cycle이 일어나고 있으므로 메모리 해제가 되지 않습니다. L에 할당된 메모리는 garbage collection이 호출되어야 해제될 수 있습니다.

댓글남기기