순환 가비지 수집 지원¶
순환 참조를 포함하는 가비지를 탐지하고 수집하는 파이썬의 지원은 역시 컨테이너일 수 있는 다른 객체의 “컨테이너” 인 객체 형의 지원이 필요합니다. 다른 객체에 대한 참조를 저장하지 않거나, 원자 형(가령 숫자나 문자열)에 대한 참조만 저장하는 형은 가비지 수집에 대한 어떤 명시적인 지원을 제공할 필요가 없습니다.
컨테이너형을 만들려면, 형 객체의 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를 추가하는 경우, 적어도
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슬롯을 채울 때, 단순히 이 매크로를 호출하는 사용자 정의 함수보다PyType_GenericAlloc()을 사용하는 것이 권장됩니다.이 매크로에 의해 할당된 메모리는
PyObject_GC_Del()을 사용하여 해제해야 합니다(보통 객체의tp_free슬롯을 통해 호출됩니다).
-
PyObject_GC_NewVar(TYPE, typeobj, size)¶
PyObject_NewVar와 유사하지만,Py_TPFLAGS_HAVE_GC플래그가 설정된 컨테이너 객체를 위한 것.객체를 위한 메모리를 할당하기 위해 이 함수를 직접 호출하지 마십시오. 대신 해당 형의
tp_alloc슬롯을 호출하십시오.형의
tp_alloc슬롯을 채울 때, 단순히 이 매크로를 호출하는 사용자 정의 함수보다PyType_GenericAlloc()을 사용하는 것이 권장됩니다.이 매크로에 의해 할당된 메모리는
PyObject_GC_Del()을 사용하여 해제해야 합니다(보통 객체의tp_free슬롯을 통해 호출됩니다).
-
PyObject *PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *type, size_t extra_size)¶
- 이것은 불안정 API. 마이너 릴리스에서 예고 없이 변경될 수 있습니다.
PyObject_GC_New와 유사하지만 객체 끝에 extra_size 바이트를 할당합니다(오프셋tp_basicsize). 할당된 메모리는Python 객체 헤더를 제외한 모든 영역이 0으로 초기화됩니다.추가 데이터는 객체와 함께 해제되지만, 그 외의 경우에는 파이썬에 의해 관리되지 않습니다.
이 함수로 할당된 메모리는
PyObject_GC_Del()을 사용하여 해제해야 합니다 (일반적으로 객체의tp_free슬롯을 통해 호출됩니다).경고
인스턴스 뒤에 추가 데이터를 예약하는 최종 메커니즘이 아직 결정되지 않았으므로 이 함수는 불안정한(unstable) 것으로 표시됩니다. 가변적인 수의 필드를 할당하려면 대신
PyVarObject와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또는 관련 할당 함수로 할당된 메모리에 이를 사용하지 마십시오. 대신PyObject_Free()를 사용하십시오.더 보기
PyObject_Free()는 이 함수의 비(non)-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함수는 인스턴스가 소유한 파이썬 객체인 각 멤버에 대해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 매개변수가 이 특정 이름을 가져야 할 것을 요구합니다. 임의의 이름으로 명명하지 마십시오.힙 할당 형 의 인스턴스는 자신의 형에 대한 참조를 보유합니다. 따라서 이들의 순회 함수는 해당 형을 방문해야 합니다:
Py_VISIT(Py_TYPE(self));
대신, 형은 힙 할당된 슈퍼클래스(또는 해당되는 경우 다른 힙 할당형)의
tp_traverse를 호출함으로써 이 책임을 위임할 수 있습니다. 그렇게 하지 않으면 해당 형 객체가 가비지 컬렉션될 수 없습니다.tp_flags필드에Py_TPFLAGS_MANAGED_DICT비트가 설정된 경우, 순회 함수는 다음과 같이PyObject_VisitManagedDict()를 호출해야 합니다:int err = PyObject_VisitManagedDict((PyObject*)self, visit, arg); if (err) { return err; }
인스턴스가 소유하는(즉, 이에 대한 강한 참조 를 갖는) 멤버만 방문해야 합니다. 예를 들어, 객체가
tp_weaklist슬롯을 통해 약한 참조를 지원하는 경우, 연결 리스트를 지원하는 포인터( tp_weaklist 가 가리키는 대상)는 인스턴스가 자신에 대한 약한 참조를 직접 소유하지 않으므로 방문해서는 안 됩니다.순회 함수에는 다음과 같은 제한이 있습니다:
경고
순회 함수는 어떠한 부수 효과도 가져서는 안 됩니다. 구현체는 직접 또는 간접적으로 어떤 파이썬 객체의 참조 횟수를 수정해서도 안 되며, 파이썬 객체를 생성하거나 파괴해서도 안 됩니다.
이는 대다수의 파이썬 C API 함수가 사용될 수 없음을 의미합니다. 해당 함수들은 새로운 예외를 발생시키거나, 결과 객체에 대한 새 참조를 반환하거나, 부수 효과를 사용하는 내부 로직을 포함할 수 있기 때문입니다. 또한 명시적으로 다른 내용이 기술되지 않는 한, 우연히 부수 효과가 없는 것으로 보이는 기능들도 경고 없이 향후 버전에서 부수 효과를 가질 수 있습니다.
안전한 함수 목록은 아래의 별도 섹션 을 참조하십시오.
참고
Py_VISIT()호출은 참조 순환에 참여할 수 없음이 증명된 멤버의 경우 생략될 수 있습니다. 위의local_traverse예제에도self->key멤버가 있지만, 이 멤버는NULL또는 파이썬 문자열만 가능하므로 참조 순환의 일부가 될 수 없습니다.반대로, 특정 멤버가 순환의 일부가 될 수 없다는 것을 알고 있더라도 디버깅을 돕기 위해 해당 멤버를 방문하도록 설정하여
gc모듈의get_referents()함수에 포함되도록 할 수도 있습니다.참고
tp_traverse함수는 모든 스레드에서 호출될 수 있습니다.가비지 수거는 “stop-the-world” 작업입니다. free threading 빌드에서도
tp_traverse핸들러가 실행될 때는 단 하나의 스레드 상태만이 attached 상태가 됩니다.버전 3.9에서 변경: 힙에 할당된 타입은
tp_traverse에서Py_TYPE(self)를 방문해야 합니다. 이전 버전의 파이썬에서는 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핸들러에서 호출될 경우,Py_TYPE()의 결과는 핸들러 호출이 지속되는 동안 유효합니다.PyObject_TypeCheck(),PyType_IsSubtype(),PyType_HasFeature()Py<type>_Check및Py<type>_CheckExact– 예:PyTuple_Check()
“DuringGC” 함수¶
다음 함수들은 오직 tp_traverse 핸들러에서만 사용해야 합니다. 다른 컨텍스트에서 호출할 경우 의도하지 않은 결과가 발생할 수 있습니다.
이 함수들은 _DuringGC 접미사가 없는 대응 함수들과 동일하게 동작하지만, 부작용이 없음을 보장하며 실패 시 예외를 발생시키지 않고 개별 문서에 명시된 대로 borrowed references 를 반환하거나 설정합니다.
이 함수들이 실패하여 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 이후로.
공통 정보는 “DuringGC” 함수 를 참조하십시오.
Added in version 3.15.
-
int PyType_GetBaseByToken_DuringGC(PyTypeObject *type, void *tp_token, PyTypeObject **result)¶
- …의 일부 안정 ABI 버전 3.15 이후로.
공통 정보는 “DuringGC” 함수 를 참조하십시오.
*result 을 강한 참조가 아닌 borrowed reference 로 설정합니다. 이 참조는
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 이후로.
공통 정보는 “DuringGC” 함수 를 참조하십시오.
이 함수들은
tp_traverse핸들러 호출이 지속되는 동안 유효한 borrowed reference 를 반환합니다.Added in version 3.15.
가비지 수거기 상태 제어하기¶
C-API는 가비지 수거 실행을 제어하기 위해 다음 함수들을 제공합니다.
-
Py_ssize_t PyGC_Collect(void)¶
- …의 일부 안정 ABI.
가비지 수거기가 활성화되어 있는 경우 전체 가비지 수거를 수행합니다. (
gc.collect()은 조건에 상관없이 실행됨을 유의하십시오.)수거되었으나 도달할 수 없어 수거되지 못한 객체의 수를 반환합니다. 가비지 수거기가 비활성화되어 있거나 이미 수거 중인 경우 즉시
0을 반환합니다. 가비지 수거 중 발생하는 오류는sys.unraisablehook으로 전달됩니다. 이 함수는 예외를 발생시키지 않습니다.
-
int PyGC_Enable(void)¶
- …의 일부 안정 ABI 버전 3.10 이후로.
가비지 수거기를 활성화합니다.
gc.enable()과 유사하며, 이전 상태를 반환합니다(비활성화 시 0, 활성화 시 1).Added in version 3.10.
-
int PyGC_Disable(void)¶
- …의 일부 안정 ABI 버전 3.10 이후로.
가비지 수거기를 비활성화합니다.
gc.disable()과 유사하며, 이전 상태를 반환합니다(비활성화 시 0, 활성화 시 1).Added in version 3.10.
-
int PyGC_IsEnabled(void)¶
- …의 일부 안정 ABI 버전 3.10 이후로.
가비지 수거기 상태를 조회합니다.
gc.isenabled()와 유사하며, 현재 상태를 반환합니다(비활성화 시 0, 활성화 시 1).Added in version 3.10.
가비지 수거기 상태 조회하기¶
C-API는 가비지 수거기에 대한 정보를 조회하기 위해 다음 인터페이스를 제공합니다.
-
void PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg)¶
- 이것은 불안정 API. 마이너 릴리스에서 예고 없이 변경될 수 있습니다.
모든 활성 GC 가능 객체에 대해 제공된 callback*을 실행합니다. *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.