STINNER Victor <vstin...@python.org> added the comment:

> test_atexit leaked [3988, 3986, 3988] references, sum=11962

The following patch fix it:

diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 7591f069b4..f088ef0bce 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -1210,6 +1210,15 @@ finalize_interp_clear(PyThreadState *tstate)
 {
     int is_main_interp = _Py_IsMainInterpreter(tstate);
 
+    _PyImport_Cleanup(tstate);
+
+    /* Explicitly break a reference cycle between the encodings module and XXX 
*/
+    PyInterpreterState *interp = tstate->interp;
+    Py_CLEAR(interp->codec_search_path);
+    Py_CLEAR(interp->codec_search_cache);
+    Py_CLEAR(interp->codec_error_registry);
+    _PyGC_CollectNoFail();
+
     /* Clear interpreter state and all thread states */
     PyInterpreterState_Clear(tstate->interp);
 
@@ -1640,7 +1649,6 @@ Py_EndInterpreter(PyThreadState *tstate)
         Py_FatalError("Py_EndInterpreter: not the last thread");
     }
 
-    _PyImport_Cleanup(tstate);
     finalize_interp_clear(tstate);
     finalize_interp_delete(tstate);
 }



Py_NewInterpreter() indirectly calls "import encodings" which calls 
codecs.register(search_function). This encodings function is stored in 
interp->codec_search_path and so keeps encodings module dict alive.

_PyImport_Cleanup() removes the last reference to the encodings *module*, but 
the module deallocator function (module_dealloc()) doesn't clear the dict: it 
only removes its strong reference to it ("Py_XDECREF(m->md_dict);").

interp->codec_search_path is cleared by PyInterpreterState_Clear() which is 
called by Py_EndInterpreter(). But it is not enough to clear some objets. I'm 
not sure if encodings module dict is still alive at this point, but it seems 
like at least the sys module dict is still alive.

I can push my workaround which manually "break a reference cycle" (really? 
which one?), but I may be interested to dig into this issue to check if we 
cannot find a better design.

_PyImport_Cleanup() and _PyModule_Clear() functions are fragile. They implement 
smart heuristics to attempt to keep Python functional as long as possible *and* 
try to clear everything. The intent is to be able to log warnings and 
exceptions during the Python shutdown, for example.

The problem is that the heuristic keeps some objects alive longer than 
expected. For example, I would expect that _PyImport_Cleanup() not only calls 
sys.modules.clear(), but also clears the dict of each module 
(module.__dict__.clear()). It doesn't, and I'm not sure why.

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue36854>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to