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

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()` を呼び出さなければなりません。

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` の対象となる全てのフィールドが正しい状態になってすぐに、たいていはコンストラクタの末尾付近で、呼び出すべきです。

void `_PyObject_GC_TRACK`(PyObject *op)

  `PyObject_GC_Track()` のマクロ版です。拡張モジュールに使ってはなりません。

  バージョン 3.6 で非推奨: このマクロは Python 3.8 から削除されます。

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

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_traverse` ハンドラの対象となるフィールドが正しくない状態になる前に、デアロケータ (`tp_dealloc` ハンドラ) はオブジェクトに対して、この関数を呼び出すべきです。

void `_PyObject_GC_UNTRACK`(PyObject *op)

  `PyObject_GC_UnTrack()` のマクロ版です。拡張モジュールに使ってはなりません。

  バージョン 3.6 で非推奨: このマクロは Python 3.8 から削除されます。

`tp_traverse` ハンドラはこの型の関数パラメータを受け取ります:

int `(*visitproc)`(PyObject *object, void *arg)

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

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

int `(*traverseproc)`(PyObject *self, visitproc visit, void *arg)

  コンテナオブジェクトのためのトラバーサル関数 (traversal function) です。実装では、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` 型であるか、オブジェクトが不変 (immutable) な場合は NULL でなければなりません。

int `(*inquiry)`(PyObject *self)

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