…imertoken
The _tkinter.tkapp and _tkinter.tktimertoken types never implemented the
garbage collector protocol, so reference cycles through an interpreter's
trace function or a timer handler's callback could not be collected.
A pending timer is kept alive by the Tcl event loop, which fires it even
after the Python token is dropped, so it is treated as a GC root (only its
callback is traversed) and collecting it never cancels a live timer. The
GC slots use a plain cast rather than the type-checking macro, since the
collector may visit a surviving object at shutdown after module clearing
has reset the global type pointers. Deallocation cancels any pending timer
so its callback cannot run on freed memory.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The internal _tkinter.tkapp and _tkinter.tktimertoken types are heap types implemented in C but never implemented the garbage collector protocol, so reference cycles through a Tcl interpreter's trace function or a timer handler's callback could not be collected.
They now implement tp_traverse and tp_clear, set Py_TPFLAGS_HAVE_GC, allocate through the type's tp_alloc, and untrack on deallocation.
Two design points differ from the earlier, reverted attempt (gh-138331, reverted by gh-138807 over the gh-138789/gh-138791 regression):
This is independent of and complementary to gh-80937 / #152294: it does not traverse the command table, so it does not collect the createcommand cycle, and that fix does not collect interpreter/timer cycles.