페이지

2022년 8월 20일 토요일

17.2 참조 카운트 방식의 메모리 관리

 파이썬 메모리 관리의 기본은 참조 참조카운트입니다. 참조 카운트는 구조가 간단하고 속도도 빠릅니다. 모든 객체는 참조 카운트가 0인 상태로 생성되고, 다른 객체가 참조할 때마다 1씩 증가합니다. 반대로 객체에 대한 참조가 끊길 때마다 1만금 감소하다가 0이 되면 파이썬 인터프리터가 회수해갑니다. 이런 방식으로 객체가 더 이상 필요 없어지면 즉시 메모리에서 삭제됩니다. 이상이 참조 카운트 방식의 매모리 관리입니다.

참고로 가령 다음과 같은 경우에 참조 카운트가 증가합니다.

1) 대입 연산자를 사용할 때

2) 함수에 인수로 전달할때

3) 컨테이너 타입 객체(리스트, 튜플, 클래스 등)에 추가할때

코드로도 예를 준비했습니다(개념을 설명하기 위한 의사코드라서 동작하지 않습니다).

class obj:
  pass

  def f(x):
    print(x)

a = obj()   # 변수에 대입: 참조 카운트 1
f(a)        # 함수에 전달: 함수 안에서 참조 카운트 2
            # 함수 완료: 빠져나오면 참조 카운트 1
a = None    # 대입 해제: 참조 카운트 0

먼저 obj()에 의해 생성된 객체를 a에 대입했습니다. 그러면 이 객체의 참조 카운트는 1입니다. 다음 줄에서 함수 f(a)를 호출하는데, 이때 a가 인수로 전달되기 때문에 함수 f의 범위 안에서는 참조 카운트가 1 증가합니다(총 2). 그리고 함수의 범위를 벗어나면 참조 카운트가 다시 1 감소합니다. 마지막으로 a = None에서 참조를 끊으면 결국 0이 됩니다(아무도 참조하지 않은 상태). 이렇게 0이 되는 즉시 해당 객체는 메모리에서 삭제됩니다.

보다시피 참조 카운트 방식은 간단합니다. 그리고 이 간단한 방식을 상용하여 수많은 메모리 문제를 해결할 수 있습니다.  다음 코드를 보시죠

a = obj()
b = obj()
c = obj()

a.b = b
b.c = c

a = b = c = None

a, b, c라는 세 개의 객체를 생성했습니다. 그리고 a가 b를 참조하고, b가 c를 참조합니다. 자. 이제 객채의 관곈느 [그림 17-1]의 왼쪽처럼 되었습니다.


그런 다음 a = b = c = None줄을 실행하면 객체의 관계는 [그림 17-1]의 오른쪽처럼 변함니다. 이때 a의 참조 카운트는 0이 됩니다(b와 c의 참조 카운트는 1입니다). 따라서 a는 즉시 삭제됩니다. 그 여파로 b의 참조 카운트가 1에서 0으로 감소하여 b역시 삭제됩니다. 똑같은 원리로 c의 참조 카운트로 0이 되어 삭제됩니다. 이렇게 사용자로부터 참조되지 않는 책체들이 마치 도미노처럼 한꺼번에 삭제되는 것입니다.

이상이 파이썬의 참조 카운트 방식 메모리 관리입니다. 이 기능이 수많은 메모리 관리 문제를 해결해 줍니다. 하지만 참조 카운트로는 해결할 수 없는 문제가 있으니, 바로 순환 참조입니다.

댓글 없음: