See also :ref:`GC bugs <gc-bugs>`.
At exit, Python calls Py_Finalize()
which is responsible to stop
Python and cleanly all states, variables, modules. etc. This code is
very fragile.
Since Python 3.6, a big refactoring started in CPython to clear more and more
variables and states at Python exit: in Py_FinalizeEx()
, but also in Python
main()
(for variables which cannot be cleared in Py_FinalizeEx()
.
Sadly, it caused some nasty issues:
When an extension module is converted to the multiphase initialization API (PEP 489), sometimes tests using subinterpreters start to leak.
2020-11-03: bpo-41796: Make _ast module state per interpreter: test_ast leaks.
FIX: Call _PyAST_Fini() earlier (commit).
Python types contain a reference to themselves in in their
PyTypeObject.tp_mro
member._PyAST_Fini()
must called before the last GC collection to destroy AST types._PyInterpreterState_Clear()
now calls_PyAST_Fini()
. It now also calls_PyWarnings_Fini()
on subinterpeters, not only on the main interpreter.Add an assertion in AST
init_types()
to ensure that the_ast
module is no longer used after_PyAST_Fini()
has been called.
2020-03-24: bpo-40050: Port _weakref to multiphase init: test_importlib started to leak.
- FIX/WORKAROUND: remove unused _weakref (and _thread) import in
importlib._bootstrap_external
(commit)
- FIX/WORKAROUND: remove unused _weakref (and _thread) import in
2020-04-02: bpo-40149: Convert _abc module to use PyType_FromSpec(): test_threading leaks.
- WORKAROUND 1 (not merged): add a second
_PyGC_CollectNoFail()
call infinalize_interp_clear()
. - FIX 1: Implement traverse in _abc._abc_data (commit)
- WORKAROUND 2 (not merged): add
Py_VISIT(Py_TYPE(self));
inabc_data_traverse()
. - Regression caused by bpo-35810: Object Initialization does not incref Heap-allocated Types?
- bpo-40217: The garbage collector doesn't take in account that objects of heap allocated types hold a strong reference to their type
- FIX 2 (bpo-40217): inject a magic function to visit the heap type in traverse functions (commit)
- FIX 3 (bpo-40217): Revert FIX 2 and traverse functions must explicitly
visit their type
(commit).
abc_data_traverse()
now callsPy_VISIT(Py_TYPE(self))
.
- WORKAROUND 1 (not merged): add a second
2019-11-22: bpo-36854: Make GC module state per-interpreter: test_atexit started to leak.
- FIX: Fix refleak in PyInit__testcapi()
- WORKAROUND: clear manually the interpreter codecs attributes (search path, search cache, error registry)
- commit
bpo-43687: use unicode_state empty string before unicode_init. without define WITH_DOC_STRINGS
- 2021-04-02: Py_Initialize() creates singletons earlier
bpo-41796: Make _ast module state per interpreter
2020-11-03: Call
_PyAST_Fini()
earlier (commit)._PyInterpreterState_Clear()
now calls_PyAST_Fini()
.
bpo-42208: Using logging or warnings during Python finalization does crash Python
2020-10-30: Call GC collect earlier in
PyInterpreterState_Clear()
(commit).The last GC collection is now done before clearing
builtins
andsys
dictionaries. Add also assertions to ensure thatgc.collect()
is no longer called after_PyGC_Fini()
.
bpo-40887: Free lists are still used after being finalized (cleared)
2020-06-08: Fix
finalize_interp_clear()
for free lists (commit).Reorganize code to ensure that free lists are cleared in the right order. Call
_PyWarnings_Fini()
before_PyList_Fini()
.
bpo-19466: Clear state of threads earlier in Python shutdown
2020-03-09:
Py_Finalize()
clears daemon threads earlier (commit).Clear the frames of daemon threads earlier during the Python shutdown to call objects destructors. So "unclosed file" resource warnings are now emitted for daemon threads in a more reliable way.
bpo-39511
2020-02-01: PyThreadState_Clear() calls on_delete (commit).
PyThreadState.on_delete
is a callback used to notify Python when a thread completes._thread._set_sentinel()
function creates a lock which is released when the thread completes. It sets on_delete callback to the internalrelease_sentinel()
function. This lock is known asThreading._tstate_lock
in the threading module.The
release_sentinel()
function uses the Python C API. The problem is that on_delete is called late in the Python finalization, when the C API is no longer fully working.The
PyThreadState_Clear()
function now calls thePyThreadState.on_delete callback
. Previously, that happened inPyThreadState_Delete()
.The
release_sentinel()
function is now called when the C API is still fully working.
bpo-36854: Make GC module state per-interpreter
2019-11-20: Clear the current thread later in the Python finalization (commit).
The
PyInterpreterState_Delete()
function is now responsible to callPyThreadState_Swap(NULL)
.The
tstate_delete_common()
function is now responsible to clear theautoTSSKey
thread local storage and it only clears it once the thread state is fully cleared. It allows to still get the current thread from TSS intstate_delete_common()
.
bpo-38858: new_interpreter() should reuse more Py_InitializeFromConfig() code
- 2019-11-20: Call
_PyExc_Fini()
and_PyGC_Fini()
later in the finalization (commit).
- 2019-11-20: Call
Main issue: bpo-1635741.
- bpo-1635741: Release Unicode interned strings at exit (commit).
https://bugs.python.org/issue23309
Commit:
commit 25f85d4bd58d86d3e6ce99cb9f270e96bf5ba08f Author: Antoine Pitrou <[email protected]> Date: Mon Apr 13 19:41:47 2015 +0200 Issue #23309: Avoid a deadlock at shutdown if a daemon thread is aborted while it is holding a lock to a buffered I/O object, and the main thread tries to use the same I/O object (typically stdout or stderr). A fatal error is emitted instead.
Code:
relax_locking = _Py_IsFinalizing(); Py_BEGIN_ALLOW_THREADS if (!relax_locking) st = PyThread_acquire_lock(self->lock, 1); else { /* When finalizing, we don't want a deadlock to happen with daemon * threads abruptly shut down while they owned the lock. * Therefore, only wait for a grace period (1 s.). * Note that non-daemon threads have already exited here, so this * shouldn't affect carefully written threaded I/O code. */ st = PyThread_acquire_lock_timed(self->lock, (PY_TIMEOUT_T)1e6, 0); } Py_END_ALLOW_THREADS if (relax_locking && st != PY_LOCK_ACQUIRED) { PyObject *msgobj = PyUnicode_FromFormat( "could not acquire lock for %A at interpreter " "shutdown, possibly due to daemon threads", (PyObject *) self); const char *msg = PyUnicode_AsUTF8(msgobj); Py_FatalError(msg); }
To workaround bpo-19565 on Windows,
multiprocessing crash at exit, _winapi.Overlapped
deallocator leaves
the overlapped handle open if Python is exiting, see the commit:
commit 633db6f6a69fd44b4a27e7e216ff7a138f69aaf3 Author: Richard Oudkerk <[email protected]> Date: Sun Nov 17 13:15:51 2013 +0000 Issue #19565: Prevent warnings at shutdown about pending overlapped ops.
- 2013-10-31: Clear state of threads earlier in Python shutdown. Call
_PyThreadState_DeleteExcept(tstate)
inPy_Finalize()
. This issue introduced corrupted a Python frame of an asyncio daemon thread which leaded to a crash: bpo-20526. I had to revert the_PyThreadState_DeleteExcept(tstate)
change.
By the time your __dealloc__()
method is called, the object may already
have been partially destroyed and may not be in a valid state as far as
Python is concerned, so you should avoid invoking any Python operations
which might touch the object. In particular, don’t call any other methods
of the object or do anything which might cause the object to be
resurrected. It’s best if you stick to just deallocating C data.
- Subinterpreters cannot spawn daemon threads anymore, since Python 3.9: https://bugs.python.org/issue37266
- In Python 3.8, daemon threads now exit immediately when they attempt to acquire the GIL, after Py_Finalize() has been called:
- change of bpo-19466 caused bpo-20526 regression