使對象類(lèi)型支持循環(huán)垃圾回收?

Python 對循環(huán)引用的垃圾檢測與回收需要“容器”對象類(lèi)型的支持,此類(lèi)型的容器對象中可能包含其它容器對象。不保存其它對象的引用的類(lèi)型,或者只保存原子類(lèi)型(如數字或字符串)的引用的類(lèi)型,不需要顯式提供垃圾回收的支持。

若要創(chuàng )建一個(gè)容器類(lèi),類(lèi)型對象的 tp_flags 字段必須包含 Py_TPFLAGS_HAVE_GC 并提供一個(gè) tp_traverse 處理的實(shí)現。如果該類(lèi)型的實(shí)例是可變的,還需要實(shí)現 tp_clear 。

Py_TPFLAGS_HAVE_GC

設置了此標志位的類(lèi)型的對象必須符合此處記錄的規則。為方便起見(jiàn),下文把這些對象稱(chēng)為容器對象。

容器類(lèi)型的構造函數必須符合兩個(gè)規則:

  1. 必須使用 PyObject_GC_New()PyObject_GC_NewVar() 為這些對象分配內存。

  2. 初始化了所有可能包含其他容器的引用的字段后,它必須調用 PyObject_GC_Track() 。

同樣的,對象的釋放器必須符合兩個(gè)類(lèi)似的規則:

  1. 在引用其它容器的字段失效前,必須調用 PyObject_GC_UnTrack() 。

  2. 必須使用 PyObject_GC_Del() 釋放對象的內存。

    警告

    如果一個(gè)類(lèi)型添加了 Py_TPFLAGS_HAVE_GC,則它 必須 實(shí)現至少一個(gè) tp_traverse 句柄或顯式地使用來(lái)自其一個(gè)或多個(gè)子類(lèi)的句柄。

    當調用 PyType_Ready() 或者 API 中某些間接調用它的函數例如 PyType_FromSpecWithBases()PyType_FromSpec() 時(shí)解釋器就自動(dòng)填充 tp_flags, tp_traversetp_clear 字段,如果該類(lèi)型是繼承自實(shí)現了垃圾回收器協(xié)議的類(lèi)并且該子類(lèi) 沒(méi)有 包括 Py_TPFLAGS_HAVE_GC 旗標的話(huà)。

TYPE *PyObject_GC_New(TYPE, PyTypeObject *type)?

類(lèi)似于 PyObject_New() ,適用于設置了 Py_TPFLAGS_HAVE_GC 標簽的容器對象。

TYPE *PyObject_GC_NewVar(TYPE, PyTypeObject *type, Py_ssize_t size)?

類(lèi)似于 PyObject_NewVar() ,適用于設置了 Py_TPFLAGS_HAVE_GC 標簽的容器對象。

TYPE *PyObject_GC_Resize(TYPE, PyVarObject *op, Py_ssize_t newsize)?

PyObject_NewVar() 所分配對象重新調整大小。 返回調整大小后的對象或在失敗時(shí)返回 NULL。 op 必須尚未被垃圾回收器追蹤。

void PyObject_GC_Track(PyObject *op)?
Part of the Stable ABI.

把對象 op 加入到垃圾回收器跟蹤的容器對象中。對象在被回收器跟蹤時(shí)必須保持有效的,因為回收器可能在任何時(shí)候開(kāi)始運行。在 tp_traverse 處理前的所有字段變?yōu)橛行Ш?,必須調用此函數,通常在靠近構造函數末尾的位置。

int PyObject_IS_GC(PyObject *obj)?

如果對象實(shí)現了垃圾回收器協(xié)議則返回非零值,否則返回 0。

如果此函數返回 0 則對象無(wú)法被垃圾回收器追蹤。

int PyObject_GC_IsTracked(PyObject *op)?
Part of the Stable ABI since version 3.9.

如果 op 對象的類(lèi)型實(shí)現了 GC 協(xié)議且 op 目前正被垃圾回收器追蹤則返回 1, 否則返回 0。

這類(lèi)似于 Python 函數 gc.is_tracked()。

3.9 新版功能.

int PyObject_GC_IsFinalized(PyObject *op)?
Part of the Stable ABI since version 3.9.

如果 op 對象的類(lèi)型實(shí)現了 GC 協(xié)議且 op 已經(jīng)被垃圾回收器終結則返回 1, 否則返回 0。

這類(lèi)似于 Python 函數 gc.is_finalized()。

3.9 新版功能.

void PyObject_GC_Del(void *op)?
Part of the Stable ABI.

釋放對象的內存,該對象初始化時(shí)由 PyObject_GC_New()PyObject_GC_NewVar() 分配內存。

void PyObject_GC_UnTrack(void *op)?
Part of the Stable ABI.

從回收器跟蹤的容器對象集合中移除 op 對象。 請注意可以在此對象上再次調用 PyObject_GC_Track() 以將其加回到被跟蹤對象集合。 釋放器 (tp_dealloc 句柄) 應當在 tp_traverse 句柄所使用的任何字段失效之前為對象調用此函數。

在 3.8 版更改: _PyObject_GC_TRACK()_PyObject_GC_UNTRACK() 宏已從公有 C API 中移除。

tp_traverse 處理接收以下類(lèi)型的函數形參。

typedef int (*visitproc)(PyObject *object, void *arg)?
Part of the Stable ABI.

傳給 tp_traverse 處理的訪(fǎng)問(wèn)函數的類(lèi)型。object 是容器中需要被遍歷的一個(gè)對象,第三個(gè)形參對應于 tp_traverse 處理的 arg 。Python核心使用多個(gè)訪(fǎng)問(wèn)者函數實(shí)現循環(huán)引用的垃圾檢測,不需要用戶(hù)自行實(shí)現訪(fǎng)問(wèn)者函數。

tp_traverse 處理必須是以下類(lèi)型:

typedef int (*traverseproc)(PyObject *self, visitproc visit, void *arg)?
Part of the Stable ABI.

用于容器對象的遍歷函數。 它的實(shí)現必須對 self 所直接包含的每個(gè)對象調用 visit 函數,visit 的形參為所包含對象和傳給處理程序的 arg 值。 visit 函數調用不可附帶 NULL 對象作為參數。 如果 visit 返回非零值,則該值應當被立即返回。

為了簡(jiǎn)化 tp_traverse 處理的實(shí)現,Python提供了一個(gè) Py_VISIT() 宏。若要使用這個(gè)宏,必須把 tp_traverse 的參數命名為 visitarg 。

void Py_VISIT(PyObject *o)?

如果 o 不為 NULL,則調用 visit 回調函數,附帶參數 oarg。 如果 visit 返回一個(gè)非零值,則返回該值。 使用此宏之后,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 類(lèi)型,如果對象不可變則為 NULL。

typedef int (*inquiry)(PyObject *self)?
Part of the Stable ABI.

丟棄產(chǎn)生循環(huán)引用的引用。不可變對象不需要聲明此方法,因為他們不可能直接產(chǎn)生循環(huán)引用。需要注意的是,對象在調用此方法后必須仍是有效的(不能對引用只調用 Py_DECREF() 方法)。當垃圾回收器檢測到該對象在循環(huán)引用中時(shí),此方法會(huì )被調用。

控制垃圾回收器狀態(tài)?

這個(gè) C-API 提供了以下函數用于控制垃圾回收的運行。

Py_ssize_t PyGC_Collect(void)?
Part of the Stable ABI.

執行完全的垃圾回收,如果垃圾回收器已啟用的話(huà)。 (請注意 gc.collect() 會(huì )無(wú)條件地執行它。)

返回已回收的 + 無(wú)法回收的不可獲取對象的數量。 如果垃圾回收器被禁用或已在執行回收,則立即返回 0。 在垃圾回收期間發(fā)生的錯誤會(huì )被傳給 sys.unraisablehook。 此函數不會(huì )引發(fā)異常。

int PyGC_Enable(void)?
Part of the Stable ABI since version 3.10.

啟用垃圾回收器:類(lèi)似于 gc.enable()。 返回之前的狀態(tài),0 為禁用而 1 為啟用。

3.10 新版功能.

int PyGC_Disable(void)?
Part of the Stable ABI since version 3.10.

禁用垃圾回收器:類(lèi)似于 gc.disable()。 返回之前的狀態(tài),0 為禁用而 1 為啟用。

3.10 新版功能.

int PyGC_IsEnabled(void)?
Part of the Stable ABI since version 3.10.

查詢(xún)垃圾回收器的狀態(tài):類(lèi)似于 gc.isenabled()。 返回當前的狀態(tài),0 為禁用而 1 為啟用。

3.10 新版功能.