순환 가비지 수집 지원¶
순환 참조를 포함하는 가비지를 탐지하고 수집하는 파이썬의 지원은 역시 컨테이너일 수 있는 다른 객체의 “컨테이너” 인 객체 형의 지원이 필요합니다. 다른 객체에 대한 참조를 저장하지 않거나, 원자 형(가령 숫자나 문자열)에 대한 참조만 저장하는 형은 가비지 수집에 대한 어떤 명시적인 지원을 제공할 필요가 없습니다.
컨테이너형을 만들려면, 형 객체의 tp_flags 필드가 Py_TPFLAGS_HAVE_GC를 포함해야 하고 tp_traverse 처리기 구현을 제공해야 합니다. 형의 인스턴스가 가변이면, tp_clear 구현도 제공해야 합니다.
Py_TPFLAGS_HAVE_GC이 플래그가 설정된 형의 객체는 여기에 설명된 규칙을 준수해야 합니다. 편의를 위해 이러한 객체를 컨테이너 객체라고 하겠습니다.
컨테이너형의 생성자는 두 가지 규칙을 준수해야 합니다:
객체의 메모리는
PyObject_GC_New나PyObject_GC_NewVar를 사용하여 할당해야 합니다.다른 컨테이너에 대한 참조를 포함할 수 있는 모든 필드가 초기화되면,
PyObject_GC_Track()를 호출해야 합니다.
마찬가지로, 객체의 할당해제자(deallocator)는 비슷한 규칙 쌍을 준수해야 합니다:
다른 컨테이너를 참조하는 필드가 무효화 되기 전에,
PyObject_GC_UnTrack()를 호출해야 합니다.객체의 메모리는
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_New나PyObject_GC_NewVar를 사용하여 객체에 할당된 메모리를 해제합니다.객체의 메모리를 해제하기 위해 이것을 직접 호출하지 말고, 대신 타입의
tp_free슬롯을 호출하십시오.PyObject_New,PyObject_NewVar, 또는 관련 할당 함수에 의해 할당된 메모리에 이것을 사용하지 말고, 대신 :c:func:`PyObject_Free`를 사용하십시오.더 보기
:c:func:`PyObject_Free`는 이 함수의 비(非)GC(가비지 컬렉션) 등가물입니다.
-
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()의 visit 및 arg 매개 변수에 특정 이름을 사용해야 합니다. 임의의 이름으로 지정하지 마십시오.: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 구현은 인자의 이름을 정확히 visit 와 arg\로 지정해야 합니다:
-
Py_VISIT(o)¶
PyObject* o 가
NULL이 아니면, o 와 arg 인자를 사용하여 visit 콜백을 호출합니다. visit 에서 0이 아닌 값이 반환되면, 그 값을 반환합니다.이는 대략 다음과 같습니다:
#define Py_VISIT(o) \ if (op) { \ int visit_result = visit(o, arg); \ if (visit_result != 0) { \ return visit_result; \ } \ }
순회 안전 함수¶
다음 함수와 매크로는 tp_traverse 핸들러에서 사용하기 안전합니다:
tp_traverse에 전달된 visit 함수Py_TYPE():tp_traverse핸들러에서 호출된 경우에만, :c:func:`!Py_TYPE`의 결과는 핸들러 호출 시간 동안 유효합니다PyObject_TypeCheck(),PyType_IsSubtype(),PyType_HasFeature()Py<type>_Check`과 :samp:`Py<type>_CheckExact– 예를 들어,PyTuple_Check()
“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_traversehandler 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.
가비지 수거기 상태 조회하기¶
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 toPyUnstable_GC_VisitObjects. Return1to continue iteration, return0to stop iteration. Other return values are reserved for now so behavior on returning anything else is undefined.Added in version 3.12.