支援迴圈垃圾回收¶
Python 對檢測和回收涉及迴圈引用的垃圾的支援,需要物件型別(這些物件型別是其他物件(也可能是容器)的“容器”)的支援。不儲存對其他物件的引用,或僅儲存對原子型別(如數字或字串)的引用的型別,不需要為垃圾回收提供任何顯式支援。
要建立容器型別,型別物件的 tp_flags
欄位必須包含 Py_TPFLAGS_HAVE_GC
,並提供 tp_traverse
處理程式的實現。如果該型別的例項是可變的,則還必須提供 tp_clear
實現。
Py_TPFLAGS_HAVE_GC
設定此標誌的型別物件必須符合此處記錄的規則。為方便起見,這些物件將被稱為容器物件。
容器型別的建構函式必須符合兩條規則:
物件的記憶體必須使用
PyObject_GC_New
或PyObject_GC_NewVar
分配。一旦所有可能包含對其他容器引用的欄位都已初始化,它必須呼叫
PyObject_GC_Track()
。
同樣,物件的解構函式也必須符合類似的規則:
在引用其他容器的欄位失效之前,必須呼叫
PyObject_GC_UnTrack()
。物件的記憶體必須使用
PyObject_GC_Del()
釋放。警告
如果型別添加了 Py_TPFLAGS_HAVE_GC,則它 必須 至少實現一個
tp_traverse
處理程式,或顯式使用其子類或超類中的處理程式。呼叫
PyType_Ready()
或間接呼叫它的某些 API(如PyType_FromSpecWithBases()
或PyType_FromSpec()
)時,如果型別繼承自實現了垃圾回收協議的類,並且子類 不 包含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
,但在物件末尾(偏移量tp_basicsize
處)分配 extra_size 位元組。除了Python 物件頭
之外,分配的記憶體初始化為零。額外資料將與物件一同釋放,但除此之外,它不受 Python 管理。
此函式分配的記憶體必須使用
PyObject_GC_Del()
釋放(通常透過物件的tp_free
槽位呼叫)。警告
此函式被標記為不穩定,因為例項之後保留額外資料的最終機制尚未確定。對於分配可變數量的欄位,建議使用
PyVarObject
和tp_itemsize
。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_GC_IsTracked(PyObject *op)¶
- 自 3.9 版本以來成為 穩定 ABI 的一部分。
如果 op 的物件型別實現了 GC 協議並且 op 當前正在被垃圾回收器跟蹤,則返回 1,否則返回 0。
這類似於 Python 函式
gc.is_tracked()
。在 3.9 版本中新增。
-
int PyObject_GC_IsFinalized(PyObject *op)¶
- 自 3.9 版本以來成為 穩定 ABI 的一部分。
如果 op 的物件型別實現了 GC 協議並且 op 已經被垃圾回收器終結,則返回 1,否則返回 0。
這類似於 Python 函式
gc.is_finalized()
。在 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()
是此函式的非 GC 等效函式。
-
void PyObject_GC_UnTrack(void *op)¶
- 作為 穩定 ABI 的一部分。
從回收器跟蹤的容器物件集合中移除物件 op。請注意,可以再次對此物件呼叫
PyObject_GC_Track()
,將其重新新增到跟蹤物件集合中。在tp_traverse
處理程式使用的任何欄位失效之前,解構函式(tp_dealloc
處理程式)應該為此物件呼叫此函式。
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 呼叫。visit 函式不能以NULL
物件引數呼叫。如果 visit 返回非零值,則應立即返回該值。Python 核心使用多個訪問器函式來實現迴圈垃圾檢測;預計使用者不需要編寫自己的訪問器函式。
tp_traverse
處理程式必須具有以下型別:
-
typedef int (*traverseproc)(PyObject *self, visitproc visit, void *arg)¶
- 作為 穩定 ABI 的一部分。
容器物件的遍歷函式。實現必須為 self 直接包含的每個物件呼叫 visit 函式,其中 visit 的引數是被包含物件和傳遞給處理程式的 arg 值。visit 函式不得使用
NULL
物件引數呼叫。如果 visit 返回非零值,則應立即返回該值。
為了簡化編寫 tp_traverse
處理程式,提供了 Py_VISIT()
宏。要使用此宏,tp_traverse
實現必須將其引數精確命名為 visit 和 arg
-
Py_VISIT(o)¶
如果 PyObject* o 不是
NULL
,則呼叫 visit 回撥,引數為 o 和 arg。如果 visit 返回非零值,則返回該值。使用此宏,tp_traverse
處理程式如下所示:static int my_traverse(Noddy *self, visitproc visit, void *arg) { Py_VISIT(self->foo); Py_VISIT(self->bar); return 0; }
tp_clear
處理程式必須是 inquiry
型別,如果物件是不可變的,則為 NULL
。
-
typedef int (*inquiry)(PyObject *self)¶
- 作為 穩定 ABI 的一部分。
釋放可能建立引用迴圈的引用。不可變物件不必定義此方法,因為它們永遠不能直接建立引用迴圈。請注意,呼叫此方法後物件仍必須有效(不要只對引用呼叫
Py_DECREF()
)。如果回收器檢測到此物件涉及引用迴圈,它將呼叫此方法。
控制垃圾回收器狀態¶
C-API 提供了以下函式來控制垃圾回收執行。
-
Py_ssize_t PyGC_Collect(void)¶
- 作為 穩定 ABI 的一部分。
如果垃圾回收器已啟用,則執行一次完整的垃圾回收。(請注意,
gc.collect()
會無條件執行它。)返回已收集 + 無法收集的不可達物件的數量。如果垃圾回收器已停用或正在收集,則立即返回
0
。垃圾回收期間的錯誤將傳遞給sys.unraisablehook
。此函式不會引發異常。
-
int PyGC_Enable(void)¶
- 自 3.10 版本以來,作為 穩定 ABI 的一部分。
啟用垃圾回收器:類似於
gc.enable()
。返回之前的狀態,0 表示停用,1 表示啟用。在 3.10 版本加入。
-
int PyGC_Disable(void)¶
- 自 3.10 版本以來,作為 穩定 ABI 的一部分。
停用垃圾回收器:類似於
gc.disable()
。返回之前的狀態,0 表示停用,1 表示啟用。在 3.10 版本加入。
-
int PyGC_IsEnabled(void)¶
- 自 3.10 版本以來,作為 穩定 ABI 的一部分。
查詢垃圾回收器的狀態:類似於
gc.isenabled()
。返回當前狀態,0 表示停用,1 表示啟用。在 3.10 版本加入。
查詢垃圾回收器狀態¶
C-API 提供了以下介面來查詢有關垃圾回收器的資訊。
-
void PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg)¶
- 這是一個不穩定 API。它可能會在次要版本中未經警告而更改。
對所有活動的、具備 GC 能力的物件執行提供的 callback。arg 會傳遞給 callback 的所有呼叫。
警告
如果回撥函式分配(或釋放)了新物件,則它們是否會被訪問是未定義的。
操作期間垃圾回收被停用。在回撥函式中顯式執行回收可能導致未定義的行為,例如多次訪問相同的物件或根本不訪問。
3.12 新版功能.
-
typedef int (*gcvisitobjects_t)(PyObject *object, void *arg)¶
要傳遞給
PyUnstable_GC_VisitObjects()
的訪問器函式的型別。arg 與傳遞給PyUnstable_GC_VisitObjects
的 arg 相同。返回1
以繼續迭代,返回0
以停止迭代。其他返回值目前保留,因此返回任何其他值的行為是未定義的。3.12 新版功能.