순환 가비지 수집 지원

순환 참조를 포함하는 가비지를 탐지하고 수집하는 파이썬의 지원은 역시 컨테이너일 수 있는 다른 객체의 《컨테이너》 인 객체 형의 지원이 필요합니다. 다른 객체에 대한 참조를 저장하지 않거나, 원자 형(가령 숫자나 문자열)에 대한 참조만 저장하는 형은 가비지 수집에 대한 어떤 명시적인 지원을 제공할 필요가 없습니다.

컨테이너형을 만들려면, 형 객체의 tp_flags 필드가 Py_TPFLAGS_HAVE_GC를 포함해야 하고 tp_traverse 처리기 구현을 제공해야 합니다. 형의 인스턴스가 가변이면, tp_clear 구현도 제공해야 합니다.

Py_TPFLAGS_HAVE_GC

이 플래그가 설정된 형의 객체는 여기에 설명된 규칙을 준수해야 합니다. 편의를 위해 이러한 객체를 컨테이너 객체라고 하겠습니다.

컨테이너형의 생성자는 두 가지 규칙을 준수해야 합니다:

  1. 객체의 메모리는 PyObject_GC_New()PyObject_GC_NewVar()를 사용하여 할당해야 합니다.

  2. 다른 컨테이너에 대한 참조를 포함할 수 있는 모든 필드가 초기화되면, PyObject_GC_Track()를 호출해야 합니다.

TYPE* PyObject_GC_New(TYPE, PyTypeObject *type)

PyObject_New()와 유사하지만, Py_TPFLAGS_HAVE_GC 플래그가 설정된 컨테이너 객체를 위한 것.

TYPE* PyObject_GC_NewVar(TYPE, PyTypeObject *type, Py_ssize_t size)

PyObject_NewVar()와 유사하지만, Py_TPFLAGS_HAVE_GC 플래그가 설정된 컨테이너 객체를 위한 것.

TYPE* PyObject_GC_Resize(TYPE, PyVarObject *op, Py_ssize_t newsize)

Resize an object allocated by PyObject_NewVar(). Returns the resized object or NULL on failure. op must not be tracked by the collector yet.

void PyObject_GC_Track(PyObject *op)

수집기가 추적하는 컨테이너 객체 집합에 객체 op를 추가합니다. 수집기는 예기치 않은 시간에 실행될 수 있으므로 추적되는 동안 객체가 유효해야 합니다. tp_traverse 처리기가 탐색하는 모든 필드가 유효해지면 호출해야 합니다, 보통 생성자의 끝부분 근처입니다.

마찬가지로, 객체의 할당해제자(deallocator)는 비슷한 규칙 쌍을 준수해야 합니다:

  1. 다른 컨테이너를 참조하는 필드가 무효화 되기 전에, PyObject_GC_UnTrack()를 호출해야 합니다.

  2. 객체의 메모리는 PyObject_GC_Del()를 사용하여 할당 해제되어야 합니다.

void PyObject_GC_Del(void *op)

PyObject_GC_New()PyObject_GC_NewVar()를 사용하여 객체에 할당된 메모리를 해제합니다.

void PyObject_GC_UnTrack(void *op)

수집기가 추적하는 컨테이너 객체 집합에서 op 객체를 제거합니다. PyObject_GC_Track()를 이 객체에 대해 다시 호출하여 추적 객체 집합에 다시 추가할 수 있음에 유의하십시오. 할당해제자(tp_dealloc 처리기)는 tp_traverse 처리기에서 사용하는 필드가 무효화 되기 전에 객체에 대해 이 함수를 호출해야 합니다.

버전 3.8에서 변경: _PyObject_GC_TRACK()_PyObject_GC_UNTRACK() 매크로는 공용 C API에서 제거되었습니다.

tp_traverse 처리기는 다음과 같은 형의 함수 매개 변수를 받아들입니다:

int (*visitproc)(PyObject *object, void *arg)

tp_traverse 처리기에 전달되는 방문자 함수의 형. 이 함수는 탐색하는 객체를 object로, tp_traverse 처리기의 세 번째 매개 변수를 arg로 호출되어야 합니다. 파이썬 코어는 순환 가비지 탐지를 구현하기 위해 여러 방문자 함수를 사용합니다; 사용자가 자신의 방문자 함수를 작성해야 할 필요는 없습니다.

tp_traverse 처리기는 다음 형이어야 합니다:

int (*traverseproc)(PyObject *self, visitproc visit, void *arg)

Traversal function for a container object. Implementations must call the visit function for each object directly contained by self, with the parameters to visit being the contained object and the arg value passed to the handler. The visit function must not be called with a NULL object argument. If visit returns a non-zero value that value should be returned immediately.

tp_traverse 처리기 작성을 단순화하기 위해, Py_VISIT() 매크로가 제공됩니다. 이 매크로를 사용하려면, tp_traverse 구현은 인자의 이름을 정확히 visitarg로 지정해야 합니다:

void Py_VISIT(PyObject *o)

If o is not NULL, call the visit callback, with arguments o and arg. If visit returns a non-zero value, then return it. Using this macro, tp_traverse handlers look like:

static int
my_traverse(Noddy *self, visitproc visit, void *arg)
{
    Py_VISIT(self->foo);
    Py_VISIT(self->bar);
    return 0;
}

The tp_clear handler must be of the inquiry type, or NULL if the object is immutable.

int (*inquiry)(PyObject *self)

참조 순환을 생성했을 수 있는 참조를 삭제합니다. 불변 객체는 참조 순환을 직접 생성할 수 없으므로, 이 메서드를 정의 할 필요가 없습니다. 이 메서드를 호출한 후에도 객체가 유효해야 합니다 (단지 참조에 대해 Py_DECREF()를 호출하지 마십시오). 이 객체가 참조 순환에 참여하고 있음을 수집기가 감지하면 이 메서드를 호출합니다.