循環参照ガベージコレクションをサポートする

Python が循環参照を含むガベージの検出とコレクションをサポートするには、他のオブジェクトに対する "コンテナ" (他のオブジェクトには他のコンテナも含みます) となるオブジェクト型によるサポートが必要です。他のオブジェクトに対する参照を記憶しないオブジェクトや、(数値や文字列のような) アトム型 (atomic type) への参照だけを記憶するような型では、ガベージコレクションに際して特別これといったサポートを提供する必要はありません。

コンテナ型を作成するには、型オブジェクトの tp_flags フィールドに Py_TPFLAGS_HAVE_GC を含め、tp_traverse ハンドラを実装する必要があります。 型のインスタンスが変更可能な場合は、tp_clear も実装する必要があります。

Py_TPFLAGS_HAVE_GC

このフラグをセットした型のオブジェクトは、この節に述べた規則に適合しなければなりません。簡単のため、このフラグをセットした型のオブジェクトをコンテナオブジェクトと呼びます。

コンテナ型のコンストラクタは以下の二つの規則に適合しなければなりません:

  1. オブジェクトのメモリは PyObject_GC_New または PyObject_GC_NewVar で割り当てなければなりません。

  2. 他のコンテナへの参照が入るかもしれないフィールドが全て初期化されたら、すぐに PyObject_GC_Track() を呼び出さなければなりません。

同様に、オブジェクトのメモリ解放関数も以下の二つの規則に適合しなければなりません:

  1. 他のコンテナを参照しているフィールドを無効化する前に、 PyObject_GC_UnTrack() を呼び出さなければなりません。

  2. オブジェクトのメモリは PyObject_GC_Del() で解放しなければなりません。

    警告

    If a type adds the Py_TPFLAGS_HAVE_GC, then it must implement at least a tp_traverse handler or explicitly use one from its subclass or subclasses.

    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)
これは Unstable APIです。マイナーリリースで予告なく変更されることがあります。

PyObject_GC_New と同様ですが、オブジェクトの末尾 (オフセット tp_basicsize) に extra_size バイトを割り当てます。 割り当てたメモリは Python オブジェクトのヘッダー を除いてゼロで初期化されます。

追加データはオブジェクトとともに解放されますが、それ以外の管理は Python では行いません。

この関数で割り当てたメモリは PyObject_GC_Del() で解放しなければなりません (通常はオブジェクトの tp_free スロットを介して呼び出します)。

警告

インスタンスの後ろに追加データを確保する最終的な仕組みが未定のため、この関数は不安定とされています。 可変個数のフィールドを割り当てるには、代わりに PyVarObject と tp_itemsize を使うことが推奨されます。

Added in version 3.12.

PyObject_GC_Resize(TYPE, op, newsize)

Resize an object allocated by PyObject_GC_NewVar. Returns the resized object of type TYPE* (refers to any C type) or NULL on failure.

op の型は PyVarObject* でなければならず、まだコレクタの追跡対象になっていてはいけません。 newsize の型は Py_ssize_t でなければなりません。

void PyObject_GC_Track(PyObject *op)
次に属します: Stable ABI.

オブジェクト op を、コレクタが追跡するコンテナオブジェクトの集合に追加します。 コレクタは予期しないタイミングで実行される可能性があるため、追跡中のオブジェクトは有効な状態でなければなりません。 tp_traverse ハンドラがたどるすべてのフィールドが有効になった時点で、通常はコンストラクタの終わり近くで呼び出してください。

int PyObject_IS_GC(PyObject *obj)

オブジェクトがガベージコレクタのプロトコルを実装している場合はゼロ以外、そうでなければ 0 を返します。

この関数が 0 を返す場合、そのオブジェクトをガベージコレクタの追跡対象にはできません。

int PyObject_GC_IsTracked(PyObject *op)
次に属します: Stable ABI (バージョン 3.9 より).

op の型が GC プロトコルを実装しており、op が現在ガベージコレクタに追跡されている場合は 1 を、それ以外の場合は 0 を返します。

Python の gc.is_tracked() 関数に相当します。

Added in version 3.9.

int PyObject_GC_IsFinalized(PyObject *op)
次に属します: Stable ABI (バージョン 3.9 より).

op の型が GC プロトコルを実装しており、op がガベージコレクタによってすでにファイナライズされている場合は 1 を、それ以外の場合は 0 を返します。

Python の gc.is_finalized() 関数に相当します。

Added in version 3.9.

void PyObject_GC_Del(void *op)
次に属します: Stable ABI.

PyObject_GC_New または PyObject_GC_NewVar でオブジェクトに割り当てたメモリを解放します。

オブジェクトのメモリを解放するために直接呼び出さず、代わりに型の tp_free スロットを呼び出してください。

PyObject_New、PyObject_NewVar、または関連する割り当て関数で割り当てたメモリには使わないでください。 代わりに PyObject_Free() を使ってください。

参考

void PyObject_GC_UnTrack(void *op)
次に属します: Stable 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)
次に属します: Stable ABI.

tp_traverse ハンドラに渡されるビジター関数 (visitor function) の型です。この関数は、探索するオブジェクトを object として、 tp_traverse ハンドラの第 3 引数を arg として呼び出します。 Python のコアはいくつかのビジター関数を使って、ゴミとなった循環参照を検出する仕組みを実装します; ユーザが自身のためにビジター関数を書く必要が出てくることはないでしょう。

tp_traverse ハンドラは次の型を持っていなければなりません:

typedef int (*traverseproc)(PyObject *self, visitproc visit, void *arg)
次に属します: Stable ABI.

Traversal function for a container object. Implementations must call the visit function for each object directly contained by self, with the parameters to visit being the contained object and the arg value passed to the handler. The visit function must not be called with a NULL object argument. If visit returns a non-zero value that value should be returned immediately.

The traversal function must not have any side effects. Implementations may not modify the reference counts of any Python objects nor create or destroy any Python objects.

To simplify writing tp_traverse handlers, a Py_VISIT() macro is provided. In order to use this macro, the tp_traverse implementation must name its arguments exactly visit and arg:

Py_VISIT(o)

If the PyObject* o is not NULL, call the visit callback, with arguments o and arg. If visit returns a non-zero value, then return it. Using this macro, tp_traverse handlers look like:

static int
my_traverse(Noddy *self, visitproc visit, void *arg)
{
    Py_VISIT(self->foo);
    Py_VISIT(self->bar);
    return 0;
}

tp_clear ハンドラは inquiry 型であるか、オブジェクトが不変 (immutable) な場合は NULL でなければなりません。

typedef int (*inquiry)(PyObject *self)
次に属します: Stable ABI.

循環参照を形成しているとおぼしき参照群を放棄します。変更不可能なオブジェクトは循環参照を直接形成することが決してないので、この関数を定義する必要はありません。このメソッドを呼び出した後でもオブジェクトは有効なままでなければならないので注意してください (参照に対して Py_DECREF() を呼ぶだけにしないでください)。ガベージコレクタは、オブジェクトが循環参照を形成していることを検出した際にこのメソッドを呼び出します。

ガベージコレクタの状態を制御する

C API は、ガベージコレクションの実行を制御するために次の関数を提供します。

Py_ssize_t PyGC_Collect(void)
次に属します: Stable ABI.

ガベージコレクタが有効な場合に、完全なガベージコレクションを実行します (gc.collect() は無条件に実行する点に注意してください)。

回収したオブジェクト数と、到達不能なのに回収できないオブジェクト数の合計を返します。 ガベージコレクタが無効か、すでに回収を実行している場合は、直ちに 0 を返します。 ガベージコレクション中のエラーは sys.unraisablehook に渡されます。 この関数は例外を送出しません。

int PyGC_Enable(void)
次に属します: Stable ABI (バージョン 3.10 より).

ガベージコレクタを有効にします。 gc.enable() に相当します。 以前の状態を返し、無効だった場合は 0、有効だった場合は 1 です。

Added in version 3.10.

int PyGC_Disable(void)
次に属します: Stable ABI (バージョン 3.10 より).

ガベージコレクタを無効にします。 gc.disable() に相当します。 以前の状態を返し、無効だった場合は 0、有効だった場合は 1 です。

Added in version 3.10.

int PyGC_IsEnabled(void)
次に属します: Stable ABI (バージョン 3.10 より).

ガベージコレクタの状態を問い合わせます。 gc.isenabled() に相当します。 現在の状態を返し、無効の場合は 0、有効の場合は 1 です。

Added in version 3.10.

ガベージコレクタの状態を問い合わせる

C API は、ガベージコレクタの情報を問い合わせるために次のインターフェースを提供します。

void PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg)
これは Unstable APIです。マイナーリリースで予告なく変更されることがあります。

生存しているすべての GC 対応オブジェクトに対して、指定された callback を実行します。 callback を呼び出すたびに arg をそのまま渡します。

警告

コールバックがオブジェクトを割り当てたり解放したりした場合、それらのオブジェクトが巡回されるかどうかは未定義です。

処理中はガベージコレクションが無効になります。 コールバック内で明示的にコレクションを実行すると、同じオブジェクトを複数回巡回したり、まったく巡回しなかったりするなど、未定義の動作を引き起こす可能性があります。

Added in version 3.12.

typedef int (*gcvisitobjects_t)(PyObject *object, void *arg)

PyUnstable_GC_VisitObjects() に渡すビジター関数の型です。 arg は PyUnstable_GC_VisitObjects に渡された arg と同じです。 反復処理を続けるには 1、停止するには 0 を返してください。 その他の戻り値は現在予約されており、これら以外の値を返した場合の動作は未定義です。

Added in version 3.12.