6

拡張モジュールで定義されたコンテナオブジェクトの循環ガベージコレクション(CGC)のサポートについてPython 2.7のドキュメントの2つのセクションで説明されています。拡張モジュールの正しい循環ガベージコレクション

Python/C API Reference Manualは、オブジェクトのメモリがPyObject_GC_New()又はPyObject_GC_NewVar()を使用して割り当てられなければならない、すなわち、

  1. 、2つのルールを与えます。
  2. 他のコンテナへの参照を含むフィールドがすべて初期化されたら、PyObject_GC_Track()を呼び出す必要があります。 Extending and Embedding the Python Interpreter

一方、Noddy例えば、Py_TPFLAGS_HAVE_GCフラグを追加し、tp_traversetp_clearスロットを充填するCGCのサポートを可能にするのに十分であろうと思われます。上記の2つのルールはまったく練習されていません。私は実際にPyObject_GC_New()/PyObject_GC_Del()PyObject_Track()/PyObject_GC_UnTrack()のルールに従うようにNoddy例を修正すると、それは驚くほど言っアサーションエラーが発生した

モジュール/ gcmodule.c:348:visit_decref:アサーション「GC →gc.gc_refs!= 0 "が失敗しました。 refcountが小さすぎました

これは、CGCを実装するための正しい/安全な方法についての私の混乱につながります。誰でも助言を与えることができますか、好ましくは、ニート CGCをサポートするコンテナオブジェクトの例ですか?

答えて

1

ほとんどの通常の状況では、追跡/追跡を自分で行う必要はありません。これはドキュメントに記載されていますが、特に明記されていません。 Noddy exampleの場合は間違いなくあなたはしません。

短いバージョンでは、TypeObjectに2つの関数ポインタ:tp_alloctp_freeが含まれています。デフォルトでは、tp_allocはクラスの作成時にすべての適切な関数を呼び出し(Py_TPFLAGS_HAVE_GCが設定されている場合)、tp_freeは破壊時にクラスをuntrackします。

Noddy documentation says(セクションの終わりに):

かなりそれです。カスタムtp_allocまたはtp_freeのスロットを作成した場合は、サイクリックガベージコレクション用に変更する必要があります。ほとんどの拡張機能は自動的に提供されるバージョンを使用します。

残念ながら、あなたがこれを自分で行う必要がないことを明確にしていない1つの場所はSupporting Cyclic Garbage Collection documentationです。


詳細:

NoddyクラスのはTypeObjecttp_newスロットにNoddy_newプットと呼ばれる機能を使用して割り当てられています。 the documentationによると、 "新しい"機能が行うべき主なことはtp_alloc slotです。通常は自分でtp_allocを書きません。デフォルトはPyType_GenericAlloc()です。

PyType_GenericAlloc() in the Python sourceには、PyType_IS_GC(type)に基づいて変更されるセクションの数が表示されます。最初にPyObject_Mallocの代わりに_PyObject_GC_Mallocを呼び出し、次に_PyObject_GC_TRACK(obj)を呼び出します。 [すべてのことPyObject_Newが本当にないことに注意してください、その後tp_initコールPyObject_Mallocとである。同様に

、割り当て解除に自動的Py_TPFLAGS_HAVE_GCとクラス用PyObject_GC_Delに設定されているtp_free slotを呼び出します。 PyObject_GC_DelにはPyObject_GC_UnTrackと同じコードが含まれているため、untrackへの呼び出しは不要です。

3

私はあなた自身にアドバイスを与えるのに十分なほどの経験はありませんが、の例の多くはPythonコンテナの実装自体にです。

個人的には、最初はタプルの実装から始めます。これは不変なのでObjects/tupleobject.cです。

が、私は助けることはできませんが、コールがあることに気づく。そして、変更可能なコンテナの上にさらにノートをdictlistset実装に移動全体でPyObject_GC_New(),PyObject_GC_NewVar()およびPyObject_GC_Track()であり、Py_TPFLAGS_HAVE_GCセットを有する。

+1

返信いただきありがとうございます。 'PyObject_GC_New()' APIのいくつかのバージョンが、AssertionErrorの原因であるサブタイプを正しく処理できない可能性を調査しています。 – liuyu

関連する問題