From db81049eb29d7bcdf2008a2f2c2b780ef3058f02 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Wed, 16 Mar 2022 18:01:10 +0100 Subject: [PATCH 1/3] Add Garbage Collection Protocol --- pep-0630.rst | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/pep-0630.rst b/pep-0630.rst index 27b4eb4e4a1..3f596f9d008 100644 --- a/pep-0630.rst +++ b/pep-0630.rst @@ -362,6 +362,46 @@ The class should generally be stored in *both* the module state (for safe access from C) and the module's ``__dict__`` (for access from Python code). + +Garbage Collection Protocol +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Instances of heap types hold a reference to their type. +This ensures that the type isn't destroyed before its instance, +but may result in reference cycles that need to be broken by the +garbage collector. + +To avoid memory leaks, instances of heap types must implement the +garbage collection protocol. +That is, heap types should: + +- Have the ``Py_TPFLAGS_HAVE_GC`` flag, +- Define a traverse function using ``Py_tp_traverse``, which + visits the type (e.g. using ``Py_VISIT(Py_TYPE(self));``). + +Please refer to the documentation of ``Py_TPFLAGS_HAVE_GC`` and +``tp_traverse`` for additional considerations. + +If your traverse function delegates to ``tp_traverse`` of its base class +(or another type), ensure that ``Py_TYPE(self)`` is visited only once. +Note that only heap type are expected to visit the type in ``tp_traverse``. + +For example, if your traverse function includes:: + + base->tp_traverse(self, visit, arg) + +...and ``base`` may be a static type, then it should also include:: + + if (base->tp_flags & Py_TPFLAGS_HEAPTYPE) { + // a heap type's tp_traverse already visited Py_TYPE(self) + } else { + Py_VISIT(Py_TYPE(self)); + } + +It is not necessary to handle the type's reference count in ``tp_new`` +and ``tp_clear``. + + Module State Access from Classes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From d64f74990c07ceca8e5fed8900dad81d7064491e Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 21 Mar 2022 17:14:18 +0100 Subject: [PATCH 2/3] Add section on Lifetime of module state --- pep-0630.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pep-0630.rst b/pep-0630.rst index 3f596f9d008..93afa4e33b9 100644 --- a/pep-0630.rst +++ b/pep-0630.rst @@ -534,6 +534,21 @@ module. C memory layout. +Lifetime of the Module State +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When a module object is varbage-collected, its module state is freed. +For each pointer to (a part of) the module state, you must hold a reference +to the module object. + +Usually this is not an issue, because types created with +``PyType_FromModuleAndSpec``, and their instances, hold a reference +to the module. +However, you must be careful in reference counting when you reference +module state from other places, such as callbacks for external +libraries. + + Open Issues ----------- From 6f51e54d0f43c3317730242c74355ff706d7b50b Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 21 Mar 2022 18:00:17 +0100 Subject: [PATCH 3/3] Apply suggestion from code review Co-authored-by: CAM Gerlach --- pep-0630.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pep-0630.rst b/pep-0630.rst index 93afa4e33b9..db1428fe23f 100644 --- a/pep-0630.rst +++ b/pep-0630.rst @@ -537,7 +537,7 @@ module. Lifetime of the Module State ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -When a module object is varbage-collected, its module state is freed. +When a module object is garbage-collected, its module state is freed. For each pointer to (a part of) the module state, you must hold a reference to the module object.