--- /dev/null
+Fixed memory leaks at interpreter shutdown in the free-threaded build, and
+also reporting of leaked memory blocks via :option:`-X showrefcount <-X>`.
#ifndef Py_GIL_DISABLED
free_work_item(ptr);
#else
- if (_PyRuntime.stoptheworld.world_stopped) {
- // Free immediately if the world is stopped, including during
- // interpreter shutdown.
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ if (_PyInterpreterState_GetFinalizing(interp) != NULL ||
+ interp->stoptheworld.world_stopped)
+ {
+ // Free immediately during interpreter shutdown or if the world is
+ // stopped.
free_work_item(ptr);
return;
}
{
#ifdef WITH_MIMALLOC
if (_PyMem_MimallocEnabled()) {
+ Py_ssize_t leaked = _PyInterpreterState_GetAllocatedBlocks(interp);
+ interp->runtime->obmalloc.interpreter_leaks += leaked;
return;
}
#endif
struct visitor_args base;
PyInterpreterState *interp;
GCState *gcstate;
+ _PyGC_Reason reason;
Py_ssize_t collected;
Py_ssize_t uncollectable;
Py_ssize_t long_lived_total;
worklist_push(&state->unreachable, op);
}
}
+ else if (state->reason == _Py_GC_REASON_SHUTDOWN &&
+ _PyObject_HasDeferredRefcount(op))
+ {
+ // Disable deferred refcounting for reachable objects as well during
+ // interpreter shutdown. This ensures that these objects are collected
+ // immediately when their last reference is removed.
+ disable_deferred_refcounting(op);
+ merge_refcount(op, 0);
+ state->long_lived_total++;
+ }
else {
// object is reachable, restore `ob_tid`; we're done with these objects
gc_restore_tid(op);
struct collection_state state = {
.interp = interp,
.gcstate = gcstate,
+ .reason = reason,
};
gc_collect_internal(interp, &state, generation);
#include "pycore_sliceobject.h" // _PySlice_Fini()
#include "pycore_sysmodule.h" // _PySys_ClearAuditHooks()
#include "pycore_traceback.h" // _Py_DumpTracebackThreads()
+#include "pycore_typeid.h" // _PyType_FinalizeIdPool()
#include "pycore_typeobject.h" // _PyTypes_InitTypes()
#include "pycore_typevarobject.h" // _Py_clear_generic_types()
#include "pycore_unicodeobject.h" // _PyUnicode_InitTypes()
_PyTypes_FiniTypes(interp);
_PyTypes_Fini(interp);
+#ifdef Py_GIL_DISABLED
+ _PyType_FinalizeIdPool(interp);
+#endif
_PyCode_Fini(interp);
#include "pycore_runtime_init.h" // _PyRuntimeState_INIT
#include "pycore_sysmodule.h" // _PySys_Audit()
#include "pycore_obmalloc.h" // _PyMem_obmalloc_state_on_heap()
-#include "pycore_typeid.h" // _PyType_FinalizeIdPool
+#include "pycore_typeid.h" // _PyType_FinalizeThreadLocalRefcounts()
/* --------------------------------------------------------------------------
CAUTION