支援迴圈垃圾回收¶
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
標誌的容器物件。
-
PyObject_GC_NewVar(TYPE, typeobj, size)¶
類似於
PyObject_NewVar
,但用於設定了Py_TPFLAGS_HAVE_GC
標誌的容器物件。
-
PyObject *PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *type, size_t extra_size)¶
- 這是 不穩定 API。它可能會在次要版本中更改,恕不另行通知。
類似於
PyObject_GC_New
,但在物件末尾(偏移量tp_basicsize
處)分配 *extra_size* 位元組。分配的記憶體初始化為零,除了Python 物件 頭
。額外的資料將隨物件一起釋放,但 Python 不會管理它。
警告
該函式被標記為不穩定,因為尚未確定在例項之後保留額外資料的最終機制。對於分配可變數量的欄位,請首選使用
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
分配給物件的記憶體。
-
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* 來呼叫。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*
-
void Py_VISIT(PyObject *o)¶
如果 *o* 不是
NULL
,則使用引數 *o* 和 *arg* 呼叫 *visit* 回撥。如果 *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 版本起為 Stable ABI 的一部分。
啟用垃圾回收器:類似於
gc.enable()
。返回之前的狀態,0 表示停用,1 表示啟用。在 3.10 版本中新增。
-
int PyGC_Disable(void)¶
- 自 3.10 版本起為 Stable ABI 的一部分。
停用垃圾回收器:類似於
gc.disable()
。返回之前的狀態,0 表示停用,1 表示啟用。在 3.10 版本中新增。
-
int PyGC_IsEnabled(void)¶
- 自 3.10 版本起為 Stable ABI 的一部分。
查詢垃圾回收器的狀態:類似於
gc.isenabled()
。返回當前狀態,0 表示停用,1 表示啟用。在 3.10 版本中新增。
查詢垃圾回收器狀態¶
C-API 提供了以下介面來查詢有關垃圾回收器的資訊。
-
void PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg)¶
- 這是 不穩定 API。它可能會在次要版本中更改,恕不另行通知。
在所有活動的、支援垃圾回收的物件上執行提供的 *callback*。*arg* 會傳遞給 *callback* 的所有呼叫。
警告
如果回撥分配(釋放)了新物件,則它們是否會被訪問是不確定的。
操作期間會停用垃圾回收。在回撥中顯式執行垃圾回收可能會導致未定義的行為,例如多次訪問相同物件或完全不訪問。
在 3.12 版本中新增。
-
typedef int (*gcvisitobjects_t)(PyObject *object, void *arg)¶
要傳遞給
PyUnstable_GC_VisitObjects()
的訪問器函式的型別。arg 與傳遞給PyUnstable_GC_VisitObjects
的 arg 相同。返回0
繼續迭代,返回1
停止迭代。其他返回值目前保留,因此返回其他任何值的行為是未定義的。在 3.12 版本中新增。