サイクリックガベージコレクションのサポート—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.8/c-api/gcsupport
移動先:案内検索

サイクリックガベージコレクションのサポート

循環参照を含むガベージの検出と収集に対するPythonのサポートには、コンテナーである可能性のある他のオブジェクトの「コンテナー」であるオブジェクトタイプからのサポートが必要です。 他のオブジェクトへの参照を格納しないタイプ、またはアトミックタイプ(数値や文字列など)への参照のみを格納するタイプは、ガベージコレクションを明示的にサポートする必要はありません。

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

Py_TPFLAGS_HAVE_GC
このフラグが設定されたタイプのオブジェクトは、ここに記載されているルールに準拠している必要があります。 便宜上、これらのオブジェクトはコンテナオブジェクトと呼ばれます。

コンテナタイプのコンストラクタは、次の2つのルールに準拠する必要があります。

  1. オブジェクトのメモリは、 PyObject_GC_New()または PyObject_GC_NewVar()を使用して割り当てる必要があります。
  2. 他のコンテナへの参照を含む可能性のあるすべてのフィールドが初期化されたら、 PyObject_GC_Track()を呼び出す必要があります。
TYPE *PyObject_GC_New(TYPE, PyTypeObject *type)
PyObject_New()に似ていますが、 Py_TPFLAGS_HAVE_GC フラグが設定されたコンテナオブジェクト用です。
TYPE *PyObject_GC_NewVar(TYPE, PyTypeObject *type, Py_ssize_t size)
PyObject_NewVar()に似ていますが、 Py_TPFLAGS_HAVE_GC フラグが設定されたコンテナオブジェクト用です。
TYPE *PyObject_GC_Resize(TYPE, PyVarObject *op, Py_ssize_t newsize)
PyObject_NewVar()によって割り当てられたオブジェクトのサイズを変更します。 サイズ変更されたオブジェクトを返します。失敗した場合はNULLを返します。 op はまだコレクターによって追跡されてはなりません。
void PyObject_GC_Track(PyObject *op)
オブジェクト op を、コレクターによって追跡されるコンテナーオブジェクトのセットに追加します。 コレクターは予期しないときに実行される可能性があるため、追跡中はオブジェクトが有効である必要があります。 これは、 tp_traverse ハンドラーが続くすべてのフィールドが有効になったら、通常はコンストラクターの終わり近くで呼び出す必要があります。

同様に、オブジェクトのデアロケーターは、同様のルールのペアに準拠する必要があります。

  1. 他のコンテナを参照するフィールドを無効にする前に、 PyObject_GC_UnTrack()を呼び出す必要があります。
  2. オブジェクトのメモリは、 PyObject_GC_Del()を使用して割り当てを解除する必要があります。
void PyObject_GC_Del(void *op)
PyObject_GC_New()または PyObject_GC_NewVar()を使用してオブジェクトに割り当てられたメモリを解放します。
void PyObject_GC_UnTrack(void *op)
コレクターによって追跡されるコンテナーオブジェクトのセットからオブジェクト op を削除します。 PyObject_GC_Track()をこのオブジェクトで再度呼び出して、追跡対象のオブジェクトのセットに追加し直すことができることに注意してください。 デアロケーター( tp_dealloc ハンドラー)は、 tp_traverse ハンドラーによって使用されるフィールドが無効になる前に、オブジェクトに対してこれを呼び出す必要があります。

バージョン3.8での変更: _PyObject_GC_TRACK()および_PyObject_GC_UNTRACK()マクロはパブリックCAPIから削除されました。


tp_traverse ハンドラーは、次のタイプの関数パラメーターを受け入れます。

typedef int (*visitproc)(PyObject *object, void *arg)
tp_traverse ハンドラーに渡されるビジター関数のタイプ。 この関数は、 object としてトラバースするオブジェクトと、 arg として tp_traverse ハンドラーへの3番目のパラメーターを指定して呼び出す必要があります。 Pythonコアは、いくつかのビジター関数を使用して、周期的なガベージ検出を実装します。 ユーザーが独自のビジター関数を作成する必要があるとは思われません。

tp_traverse ハンドラーは、次のタイプである必要があります。

typedef int (*traverseproc)(PyObject *self, visitproc visit, void *arg)
コンテナオブジェクトのトラバーサル関数。 実装は、 self に直接含まれる各オブジェクトに対して visit 関数を呼び出す必要があります。この場合、 visit のパラメーターは含まれるオブジェクトであり、 arg ハンドラーに渡される値。 visit 関数は、NULLオブジェクト引数を使用して呼び出すことはできません。 visit がゼロ以外の値を返す場合、その値はすぐに返される必要があります。

tp_traverse ハンドラーの記述を簡素化するために、 Py_VISIT()マクロが提供されています。 このマクロを使用するには、 tp_traverse 実装で引数に正確に visit および arg という名前を付ける必要があります。

void Py_VISIT(PyObject *o)

oNULLでない場合は、引数 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)
参照サイクルを作成した可能性のある参照を削除します。 不変オブジェクトは、参照サイクルを直接作成できないため、このメソッドを定義する必要はありません。 このメソッドを呼び出した後も、オブジェクトは引き続き有効である必要があることに注意してください(参照で Py_DECREF()を呼び出すだけではありません)。 コレクターは、このオブジェクトが参照サイクルに関与していることを検出すると、このメソッドを呼び出します。