Repository navigation
Heap types implemented in C must have Py_TPFLAGS_HAVE_GC and implement tp_traverse #116946
Copy link
Copy link
Open
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
If a heap type does not have Py_TPFLAGS_HAVE_GC or doesn't not implement tp_traverse, the garbage collector may fail to collect the type and most of its instances at Python exit. The problem is worse when sub-interpreters are involved: if a sub-interpreter exits and does not clear all of its memory, the other interpreters will continue running with these leaks.
See issue gh-87138 for the rationale.
I wrote an article on the lock type which had this bug and caused a memory leak: https://vstinner.github.io/subinterpreter-leaks.html
Linked PRs
- [draft] gh-116946: Emit RuntimeError if a heap type does not implement traverse #116947
- gh-116946: fully implement GC protocol for
zlibobjects #138290 - [3.14] gh-116946: fully implement GC protocol for
zlibobjects (GH-138290) #138327 - [3.13] gh-116946: fully implement GC protocol for
zlibobjects (GH-138290) #138328 - gh-116946: fully implement GC protocol for
_tkinter.Tk{app,tt}Object#138331 - gh-116946: fully implement GC protocol for
_curses_panel.panel#138333 - [3.14] gh-116946: fully implement GC protocol for
_curses_panel.panel(GH-138333) #138427 - [3.13] gh-116946: fully implement GC protocol for
_curses_panel.panel(GH-138333) #138428 - gh-116946: fully implement GC protocol for
_functools._lru_list_elem#138334 - gh-116946: add
Py_TPFLAGS_IMMUTABLETYPEtoselect.[e]poll#138340 - gh-116946: add
Py_TPFLAGS_IMMUTABLETYPEto_random.Random#138341 - gh-116946: add
Py_TPFLAGS_IMMUTABLETYPEto several internal types #138582 - Revert "gh-116946: fully implement GC protocol for
_tkinter.Tk{app,tt}Object(#138331)" #138807 - gh-116946: Remove gc-support from some immutable types #139073
- gh-116946: partial revert gh-139073 for thread handle type #139474
- GH-116946: Eliminate the need for the GC in the
_thread.lockand_thread.RLock#141268 - GH-116946: revert eliminate the need for the GC in the
_thread.lockand_thread.RLock#141448 - gh-116946: Implement the GC protocol for _tkinter tkapp and tktimertoken #152310
- gh-116946: remove unnecessary gc from _decimal types #156034
The following PRs were directly closed because the types are immutable and empty:
- gh-116946: fully implement GC protocol for
_thread._localdummy#138329 - gh-116946: fully implement GC protocol for
_tokenize.TokenizerIter#138330 - gh-116946: fully implement GC protocol for
_ssl.Certificate#138332
The following PRs were wrongly merged so we reverted them:
- gh-116946: fully implement GC protocol for
bz2objects #138266 - [3.14] gh-116946: fully implement GC protocol for
bz2objects (GH-138266) #138320 - [3.13] gh-116946: fully implement GC protocol for
bz2objects (GH-138266) #138322 - gh-116946: fully implement GC protocol for
lzmaobjects #138288 - [3.14] gh-116946: fully implement GC protocol for
lzmaobjects (GH-138288) #138321 - [3.13] gh-116946: fully implement GC protocol for
lzmaobjects (GH-138288) #138323 - gh-116946: fully implement GC protocol for
_hashlibobjects #138289 - [3.14] gh-116946: fully implement GC protocol for
_hashlibobjects (GH-138289) #138324 - [3.13] gh-116946: fully implement GC protocol for
_hashlibobjects (GH-138289) #138326
PRs for reverting the above commits:
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Activity
pythongh-116946: Emit RuntimeError if a heap does not implement traverse
vstinner commentedon Mar 18, 2024
vstinner commentedon Mar 18, 2024
See also issue gh-116915 "test_capi leaks references" and PR gh-116934 "Make _thread._ThreadHandle support GC" which fix it.
picnixz commentedon Aug 30, 2025
I use the following convention:
The following items may need to support the GC protocol or be made immutable. Once this is done, this first list must be empty and each of its member will be moved to one of the lists below (may be present in more than one list).
The following types are true container types that should support the GC protocol and have reference cycles with public documented API only. In particular, the corresponding PRs need to be backported.
The following types are true container types that should support the GC protocol. This list tracks, in addition, their immutability in main (if this is not already the case):
The following types are empty (or their attributes cannot be used to create cycles) and can be made immutable in main. Non-immutable trivial types are left as is in bugfix versions to alleviate the burden on the GC even if it's possible to create reference cycles manually (and require the user to dig into implementation details):
The following types are immutable and empty (or cannot create cycles), hence do not need the GC. If they do implement the GC protocol, they should be simplified.
The following types are immutable but not empty, but really internal.
Visiting them is delegated to someone else:
functools._lru_list_elemFinally, the following types are explicitly required to be missing the GC (testing purposes):
_testcapi.HeapCTypeSetattr_testcapi.HeapCType_testcapi.HeapCTypeSubclass_testcapi.HeapCTypeSubclassWithFinalizer(inherits_testcapi.HeapCTypeSubclass)The following should require the GC protocol. Currently the tests do not leak, but they could if we were to store the instance as one of its attribute. Nevertheless, since we're only testing them once, I suggest we leave them alone.
The following testing types are also empty or trivial:
_testcapi.HeapCTypeVectorcall_testcapi.HeapCTypeWithBuffer_testcapi.HeapDocCType_testcapi.NullTpDocType_testcapi.PyUnicodeWriter_testcapi._test_structmembersType_NewAPI_testimportexec.Str_testlimitedcapi.LimitedRelativeVectorCallClass_testlimitedcapi.LimitedVectorCallClassxxlimited_35.Nullxxlimited_35.Strxxlimited.StrThe following testing types are non-empty but do not own the references:
_testcapi.HeapCTypeWithRelativeWeakref_testcapi.HeapCTypeWithWeakref2_testcapi.HeapCTypeWithWeakrefFootnotes
Backports delayed until https://github.com/python/cpython/issues/138791 is fixed. ↩ ↩2
pythongh-116946: fully implement GC protocol for `lzma` objects
pythongh-116946: fully implement GC protocol for `lzma` objects
gh-116946: fully implement GC protocol for `bz2` objects (#138266)
pythongh-116946: fully implement GC protocol for `bz2` objects (pytho…
gh-116946: fully implement GC protocol for `lzma` objects (#138288)
gh-116946: fully implement GC protocol for `_hashlib` objects (#138289)
64 remaining items
kumaraditya303 commentedon Oct 1, 2025
That wasn't a real refleak and it occurred because register_at_fork was called, which the refleak checker mistakenly identifies as a leak. This is a known, longstanding issue in CPython that fork handlers cannot be cleared.
See this comment
cpython/Lib/test/test_posix.py
Lines 243 to 245 in ce23eea
gh-116946: remove unnecessary gc from immutable types (#139073)
Revert "pythongh-116946: remove unnecessary gc from immutable types (p…
gh-116946: partial revert gh-139073 for thread handle type (#139474)
GH-116946: eliminate the need for the GC in the `_thread.lock` and `_…
Revert "pythonGH-116946: eliminate the need for the GC in the `_threa…
GH-116946: revert eliminate the need for the GC in the `_thread.lock`…
pythonGH-116946: eliminate the need for the GC in the `_thread.lock` …
pythonGH-116946: revert eliminate the need for the GC in the `_thread…
vfazio commentedon Apr 11, 2026
I'm in the process of trying to convert a single phase init module (https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/tree/bindings/python/tests/gpiosim/ext.c) over to multi-phase init in light of PEP 793 looking to soft deprecate PyInit_*.
I'm trying to keep up with the back and forth on
Py_TPFLAGS_IMMUTABLETYPEand types created viaPyType_FromModuleAndSpecwhich arePy_TPFLAGS_HEAPTYPE.In our case, the type does need access to module state, so needs to be a heap type after the transition.
What's not clear is whether I also need to define this as
Py_TPFLAGS_HAVE_GCand definetp_traverse. It looks like the standard modules likebz2(which is probably our closest analogue) has been marked GC, unmarked GC, and maybe still under consideration to be added back #139073 (comment)If I'm reading #118021 (comment) correctly, if a heap type is created via
PyType_FromSpecand thus has no module ref, it may be possible to avoid the GC flag, otherwise if using methods likePyType_FromModuleAndSpecorPyType_FromMetaclasswith a module argument, then there may be a need to add the GC flag and atp_traversemethod?Pep 573 https://peps.python.org/pep-0573/#adding-module-references-to-heap-types:
Have there been any new discoveries or is there any clarification on what's recommended for C extension maintainers? Just looking for some guidance, otherwise I may just punt on converting this until this issue has been resolved.
serhiy-storchaka commentedon Jun 26, 2026
PR #152310 reimplements the GC protocol for
tkappandtktimertoken, addressing the two problems that led to the gh-138331 revert (gh-138807):module_clear()has reset the global type pointers.Both are covered by regression tests.
pythongh-116946: Implement the GC protocol for _tkinter tkapp and tkt…
gh-116946: Implement the GC protocol for _tkinter tkapp and tktimerto…
skirpichev commentedon Aug 16, 2026
I think we should create a separate documentation issue. @serhiy-storchaka ?
As currently we have following advice in docs:
If that's actually optional, I believe it worth to be documented. Using GC-enabled immutable heap types come with a noticeable performance loss. Here is an example for the
_decimalmodule: skirpichev#24