Python

순환 가비지 수집 지원

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

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

Py_TPFLAGS_HAVE_GC

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

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

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

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

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

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

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

    경고

    타입이 Py_TPFLAGS_HAVE_GC`를 추가하는 경우, *반드시* 적어도 :c:member:`~PyTypeObject.tp_traverse 핸들러를 구현하거나 하위 클래스 또는 하위 클래스 중 하나에서 명시적으로 사용해야 합니다.

    PyType_Ready() 를 호출하거나 PyType_FromSpecWithBases() 또는 PyType_FromSpec() 처럼 간접적으로 호출하는 API의 경우, 해당 타입이 가비지 컬렉터 프로토콜을 구현하는 클래스를 상속받고 자식 클래스가 Py_TPFLAGS_HAVE_GC 플래그를 포함하지 않으면, 인터프리터는 tp_flags, tp_traverse, 그리고 tp_clear 필드를 자동으로 채웁니다.

PyObject_GC_New(TYPE, typeobj)

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

메모리 할당을 위해 이 함수를 직접 호출하지 마십시오. 대신 타입의 tp_alloc 슬롯을 호출하십시오.

타입의 tp_alloc 슬롯을 채울 때는, 이 매크로를 단순히 호출하는 사용자 정의 함수보다 :c:func:`PyType_GenericAlloc`이 선호됩니다.

이 매크로로 할당된 메모리는 PyObject_GC_Del() 을 사용하여 해제해야 합니다 (일반적으로 객체의 tp_free 슬롯을 통해 호출됩니다).

PyObject_GC_NewVar(TYPE, typeobj, size)

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

메모리 할당을 위해 이 함수를 직접 호출하지 마십시오. 대신 타입의 tp_alloc 슬롯을 호출하십시오.

타입의 tp_alloc 슬롯을 채울 때는, 이 매크로를 단순히 호출하는 사용자 정의 함수보다 :c:func:`PyType_GenericAlloc`이 선호됩니다.

이 매크로로 할당된 메모리는 PyObject_GC_Del() 을 사용하여 해제해야 합니다 (일반적으로 객체의 tp_free 슬롯을 통해 호출됩니다).

PyObject *PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *type, size_t extra_size)
이것은 불안정 API. 경고 없이 사소 버전에서 변경될 수 있습니다.

:c:macro:`PyObject_GC_New`와 유사하지만, 객체의 끝에 extra_size 바이트를 할당합니다 (오프셋 :c:member:`~PyTypeObject.tp_basicsize`에서). 할당된 메모리는 :c:type:`Python object header <PyObject>`를 제외하고 0으로 초기화됩니다.

추가 데이터는 객체와 함께 해제되지만, 그 외의 경우에는 파이썬에서 관리되지 않습니다.

이 함수로 할당된 메모리는 PyObject_GC_Del() 을 사용하여 해제해야 합니다 (일반적으로 객체의 tp_free 슬롯을 통해 호출됩니다).

경고

함수는 인스턴스 이후에 추가 데이터 공간을 예약하기 위한 최종 메커니즘이 아직 결정되지 않았기 때문에 불안정(unstable)으로 표시되어 있습니다. 가변 개수의 필드를 할당하려면 대신 :c:type:`PyVarObject`와 :c:member:`~PyTypeObject.tp_itemsize`를 사용하는 것이 좋습니다.

Added in version 3.12.

PyObject_GC_Resize(TYPE, op, newsize)

PyObject_NewVar에 의해 할당된 객체의 크기를 변경합니다. 형 TYPE* (모든 C 형을 나타냅니다) 의 크기가 조정된 객체나 실패하면 NULL을 반환합니다.

op는 형 PyVarObject*이어야 하고 아직 수거기가 추적하지 않아야 합니다. newsize는 형 Py_ssize_t이어야 합니다.

void PyObject_GC_Track(PyObject *op)
상의 안정 ABI.

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

int PyObject_IS_GC(PyObject *obj)

객체가 가비지 수거기 프로토콜을 구현하면 0이 아닌 값을 반환하고, 그렇지 않으면 0을 반환합니다.

이 함수가 0을 반환하면 가비지 수거기가 객체를 추적할 수 없습니다.

int PyObject_GC_IsTracked(PyObject *op)
상의 안정 ABI 버전 3.9 이후로.

op의 객체 형이 GC 프로토콜을 구현하고 op가 현재 가비지 수거기가 추적 중이면 1을 반환하고 그렇지 않으면 0을 반환합니다.

이것은 파이썬 함수 gc.is_tracked()에 해당합니다.

Added in version 3.9.

int PyObject_GC_IsFinalized(PyObject *op)
상의 안정 ABI 버전 3.9 이후로.

op의 객체 형이 GC 프로토콜을 구현하고 가비지 수거기가 op를 이미 파이널라이즈 했으면 1을 반환하고 그렇지 않으면 0을 반환합니다.

이것은 파이썬 함수 gc.is_finalized()에 해당합니다.

Added in version 3.9.

void PyObject_GC_Del(void *op)
상의 안정 ABI.

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

객체의 메모리를 해제하기 위해 이것을 직접 호출하지 말고, 대신 타입의 tp_free 슬롯을 호출하십시오.

PyObject_New, PyObject_NewVar, 또는 관련 할당 함수에 의해 할당된 메모리에 이것을 사용하지 말고, 대신 :c:func:`PyObject_Free`를 사용하십시오.

더 보기

void PyObject_GC_UnTrack(void *op)
상의 안정 ABI.

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

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

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

typedef int (*visitproc)(PyObject *object, void *arg)
상의 안정 ABI.

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

tp_clear 처리기는 inquiry 형이거나 객체가 불변이면 NULL이어야 합니다.

typedef int (*inquiry)(PyObject *self)
상의 안정 ABI.

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

순회

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

typedef int (*traverseproc)(PyObject *self, visitproc visit, void *arg)
상의 안정 ABI.

가비지 컬렉션된 객체를 위한 순회 함수로, 가비지 컬렉터가 참조 순환을 감지하는 데 사용됩니다. 구현은 self 에 직접 포함된 각 객체에 대해 visit 함수를 호출해야 하며, visit 에 대한 매개 변수는 포함된 객체와 핸들러에 전달된 arg 값입니다. visit 함수는 NULL 객체 인자로 호출해서는 안 됩니다. visit 이 0이 아닌 값을 반환하면 즉시 이 값을 반환해야 합니다.

일반적인 tp_traverse 함수는 인스턴스가 소유하는 Python 객체인 인스턴스의 각 멤버에 대해 Py_VISIT() 편의 매크로를 호출합니다. 예를 들어, 이것은 threading.local 클래스에 대한 (약간 오래된) 순회 함수입니다.

static int
local_traverse(PyObject *op, visitproc visit, void *arg)
{
    localobject *self = (localobject *) op;
    Py_VISIT(Py_TYPE(self));
    Py_VISIT(self->args);
    Py_VISIT(self->kw);
    Py_VISIT(self->dict);
    return 0;
}

참고

Py_VISIT()local_traverse()visitarg 매개 변수에 특정 이름을 사용해야 합니다. 임의의 이름으로 지정하지 마십시오.

:ref:`heap-allocated types <heap-types>`의 인스턴스는 자신의 타입에 대한 참조를 가집니다. 따라서 해당 순회 함수는 타입을 방문해야 합니다:

Py_VISIT(Py_TYPE(self));

대안으로, 타입은 힙 할당된 슈퍼클래스(또는 적용 가능한 다른 힙 할당 타입)의 tp_traverse 를 호출하여 이 책임을 위임할 수 있습니다. 그렇지 않으면 타입 객체가 가비지 컬렉션되지 않을 수 있습니다.

만약 tp_flags 필드에 Py_TPFLAGS_MANAGED_DICT 비트가 설정되어 있다면, 순회 함수는 다음과 같이 :c:func:`PyObject_VisitManagedDict`를 호출해야 합니다:

int err = PyObject_VisitManagedDict((PyObject*)self, visit, arg);
if (err) {
    return err;
}

인스턴스가 소유하는 멤버(이에 대한 strong references <strong reference>`를 가짐으로써)만 방문되어야 합니다. 예를 들어, 객체가 :c:member:`~PyTypeObject.tp_weaklist 슬롯을 통해 약한 참조를 지원하는 경우, ( tp_weaklist*가 가리키는) 연결 리스트를 지원하는 포인터는 인스턴스가 자신에 대한 약한 참조를 직접 소유하지 않으므로 방문해서는 **안 됩니다*.

순회 함수는 제한 사항이 있습니다:

경고

순회 함수는 어떤 부작용도 가져서는 안 됩니다. 구현은 어떤 Python 객체의 참조 카운트를 수정하거나, 직접적이든 간접적이든 어떤 Python 객체를 생성하거나 파괴해서는 안 됩니다.

이는 해당 함수들이 새로운 예외를 발생시키거나, 결과 객체에 대한 새로운 참조를 반환하거나, 부작용을 사용하는 내부 논리를 가지고 있을 수 있으므로 대부분 의 Python C API 함수를 사용하지 못할 수 있음을 의미합니다. 또한, 달리 문서화되어 있지 않은 한, 부작용이 없는 것으로 간주되는 함수라도 경고 없이 향후 버전에서 부작용을 가질 수 있습니다.

안전한 함수 목록은 아래의 :ref:`separate section <duringgc-functions>`를 참조하십시오.

참고

Py_VISIT() 호출은 참조 순환에 참여할 수 없음을 확실히 증명할 수 있는 멤버에 대해서는 건너뛸 수 있습니다. 상단의 local_traverse 예제에는 self->key 멤버도 있지만, 이는 NULL 또는 Python 문자열만 될 수 있으므로 참조 순환의 일부가 될 수 없습니다.

반면에, 멤버가 순환의 일부가 될 수 없다는 것을 알더라도, 디버깅 지원을 위해 gc 모듈의 get_referents() 함수가 해당 멤버를 포함하도록 어쨌든 방문하고 싶을 수 있습니다.

참고

tp_traverse 함수는 모든 스레드에서 호출될 수 있습니다.

가비지 컬렉션은 “스톱-더-월드” 작업입니다: free threading 빌드에서도, tp_traverse 핸들러가 실행될 때 하나의 스레드 상태만 attached 상태로 있게 됩니다.

버전 3.9에서 변경: 히프 할당된 타입은 tp_traverse 에서 Py_TYPE(self) 를 방문해야 합니다. 이전 버전의 Python에서는 bug 40217 로 인해 이를 수행할 경우 하위 클래스에서 충돌이 발생할 수 있습니다.

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

Py_VISIT(o)

PyObject* oNULL 이 아니면, oarg 인자를 사용하여 visit 콜백을 호출합니다. visit 에서 0이 아닌 값이 반환되면, 그 값을 반환합니다.

이는 대략 다음과 같습니다:

#define Py_VISIT(o)                             \
   if (op) {                                    \
      int visit_result = visit(o, arg);         \
      if (visit_result != 0) {                  \
         return visit_result;                   \
      }                                         \
   }

순회 안전 함수

다음 함수와 매크로는 tp_traverse 핸들러에서 사용하기 안전합니다:

“DuringGC” 함수

다음 함수들은 tp_traverse 핸들러에서 사용해야 하며, 다른 컨텍스트에서 호출할 경우 의도하지 않은 결과를 초래할 수 있습니다.

이 함수들은 _DuringGC 접미사가 없는 대응 함수처럼 작동하지만, 부작용이 없다는 것이 보장되며, 실패 시 예외를 설정하지 않으며, 개별 문서에 자세히 설명된 대로 :term:`빌린 참조 <borrowed reference>`를 반환/설정합니다.

이 함수들은 실패할 수 있음(NULL 또는 -1 반환)에 유의하십시오. 하지만 예외를 설정하지 않기 때문에, 오류 정보는 이용할 수 없습니다. 경우에 따라 실패가 성공적인 NULL 결과와 구별되지 않을 수 있습니다.

void *PyObject_GetTypeData_DuringGC(PyObject *o, PyTypeObject *cls)
void *PyObject_GetItemData_DuringGC(PyObject *o)
void *PyType_GetModuleState_DuringGC(PyTypeObject *type)
void *PyModule_GetState_DuringGC(PyObject *module)
int PyModule_GetToken_DuringGC(PyObject *module, void **result)
상의 안정 ABI 버전 3.15 이후로.

공통 정보는 :ref:`duringgc-functions`를 참조하십시오.

Added in version 3.15.

int PyType_GetBaseByToken_DuringGC(PyTypeObject *type, void *tp_token, PyTypeObject **result)
상의 안정 ABI 버전 3.15 이후로.

공통 정보는 :ref:`duringgc-functions`를 참조하십시오.

*result 를 강력한 참조가 아닌 빌린 참조 로 설정합니다. 이 참조는 tp_traverse 핸들러 호출 시간 동안 유효합니다.

Added in version 3.15.

PyObject *PyType_GetModule_DuringGC(PyTypeObject *type)
PyObject *PyType_GetModuleByToken_DuringGC(PyTypeObject *type, const void *mod_token)
반환값: 빌린 참조. 상의 안정 ABI 버전 3.15 이후로.

공통 정보는 :ref:`duringgc-functions`를 참조하십시오.

These functions return a borrowed reference, which is valid for the duration of the tp_traverse handler call.

Added in version 3.15.

가비지 수거기 상태 제어하기

C-API는 가비지 수집 실행을 제어하기 위한 다음 함수들을 제공합니다.

Py_ssize_t PyGC_Collect(void)
상의 안정 ABI.

가비지 수거기가 활성화된 경우, 전체 가비지 수거를 수행합니다. (:func:`gc.collect`는 무조건적으로 이를 실행한다는 점에 유의하십시오.)

수거할 수 없거나 도달 불가능한 수거된 객체의 수를 반환합니다. 가비지 수거기가 비활성화되었거나 이미 수집 중인 경우, 즉시 0 을 반환합니다. 가비지 수거 중 발생한 오류는 sys.unraisablehook 으로 전달됩니다. 이 함수는 예외를 발생시키지 않습니다.

int PyGC_Enable(void)
상의 안정 ABI 버전 3.10 이후로.

가비지 수거기를 활성화합니다. :func:`gc.enable`과 유사합니다. 이전 상태(비활성 시 0, 활성 시 1)를 반환합니다.

Added in version 3.10.

int PyGC_Disable(void)
상의 안정 ABI 버전 3.10 이후로.

가비지 수거기를 비활성화합니다. :func:`gc.disable`과 유사합니다. 이전 상태(비활성 시 0, 활성 시 1)를 반환합니다.

Added in version 3.10.

int PyGC_IsEnabled(void)
상의 안정 ABI 버전 3.10 이후로.

가비지 수거기의 상태를 조회합니다: :func:`gc.isenabled`과 유사합니다. 현재 상태(비활성 시 0, 활성 시 1)를 반환합니다.

Added in version 3.10.

가비지 수거기 상태 조회하기

C-API는 가비지 수거기에 대한 정보를 조회할 다음 인터페이스를 제공합니다.

void PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg)
이것은 불안정 API. 경고 없이 사소 버전에서 변경될 수 있습니다.

제공된 callback*을 모든 살아있는 GC-기능 객체에 실행합니다. *arg*는 *callback 호출 모든 곳으로 전달됩니다.

경고

콜백에 의해 새 객체가 (할당/해제)되는 경우, 해당 객체가 방문될지 여부는 정의되지 않습니다.

작동 중에는 가비지 수거가 비활성화됩니다. 콜백에서 명시적으로 수거를 실행하면, 동일한 객체를 여러 번 방문하거나 아예 방문하지 않게 되는 등 정의되지 않은 동작을 초래할 수 있습니다.

Added in version 3.12.

typedef int (*gcvisitobjects_t)(PyObject *object, void *arg)

Type of the visitor function to be passed to PyUnstable_GC_VisitObjects(). arg is the same as the arg passed to PyUnstable_GC_VisitObjects. Return 1 to continue iteration, return 0 to stop iteration. Other return values are reserved for now so behavior on returning anything else is undefined.

Added in version 3.12.

분실물 보관소