支援迴圈垃圾回收

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()

同樣,物件的釋放器必須符合類似的一對規則:

  1. 在使引用其他容器的欄位失效之前,必須呼叫 PyObject_GC_UnTrack()

  2. 必須使用 PyObject_GC_Del() 釋放物件的記憶體。

    警告

    如果型別添加了 Py_TPFLAGS_HAVE_GC,那麼它必須至少實現一個 tp_traverse 處理程式,或者顯式使用其子類或子類的處理程式。

    當呼叫 PyType_Ready() 或一些間接呼叫它的 API(如 PyType_FromSpecWithBases()PyType_FromSpec())時,如果該型別繼承自實現了垃圾回收器協議的類,並且子類包含 Py_TPFLAGS_HAVE_GC 標誌,則直譯器將自動填充 tp_flagstp_traversetp_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 不會管理它。

警告

該函式被標記為不穩定,因為尚未確定在例項之後保留額外資料的最終機制。對於分配可變數量的欄位,請首選使用 PyVarObjecttp_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_IS_GC(PyObject *obj)

如果物件實現了垃圾回收器協議,則返回非零值,否則返回 0。

如果此函式返回 0,則該物件不能被垃圾回收器跟蹤。

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_NewPyObject_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_VisitObjectsarg 相同。返回 0 繼續迭代,返回 1 停止迭代。其他返回值目前保留,因此返回其他任何值的行為是未定義的。

在 3.12 版本中新增。