mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Issue #477863: Print a warning at shutdown if gc.garbage is not empty.
This commit is contained in:
parent
2e5f1178ac
commit
696e03553b
7 changed files with 99 additions and 10 deletions
|
@ -177,6 +177,15 @@ value but should not rebind it):
|
||||||
If :const:`DEBUG_SAVEALL` is set, then all unreachable objects will be added to
|
If :const:`DEBUG_SAVEALL` is set, then all unreachable objects will be added to
|
||||||
this list rather than freed.
|
this list rather than freed.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.2
|
||||||
|
If this list is non-empty at interpreter shutdown, a warning message
|
||||||
|
gets printed:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
gc: 2 uncollectable objects at shutdown:
|
||||||
|
Use gc.set_debug(gc.DEBUG_UNCOLLECTABLE) to list them.
|
||||||
|
|
||||||
The following constants are provided for use with :func:`set_debug`:
|
The following constants are provided for use with :func:`set_debug`:
|
||||||
|
|
||||||
|
|
||||||
|
@ -197,6 +206,9 @@ The following constants are provided for use with :func:`set_debug`:
|
||||||
reachable but cannot be freed by the collector). These objects will be added to
|
reachable but cannot be freed by the collector). These objects will be added to
|
||||||
the ``garbage`` list.
|
the ``garbage`` list.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.2
|
||||||
|
Also print the contents of the :data:`garbage` list at interpreter
|
||||||
|
shutdown (rather than just its length), if it isn't empty.
|
||||||
|
|
||||||
.. data:: DEBUG_SAVEALL
|
.. data:: DEBUG_SAVEALL
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,11 @@ New, Improved, and Deprecated Modules
|
||||||
* The :class:`ftplib.FTP` class now supports the context manager protocol
|
* The :class:`ftplib.FTP` class now supports the context manager protocol
|
||||||
(Contributed by Tarek Ziadé and Giampaolo Rodolà; :issue:`4972`.)
|
(Contributed by Tarek Ziadé and Giampaolo Rodolà; :issue:`4972`.)
|
||||||
|
|
||||||
|
* A warning message will now get printed at interpreter shutdown if
|
||||||
|
the :data:`gc.garbage` list isn't empty. This is meant to make the
|
||||||
|
programmer aware that his code contains object finalization issues.
|
||||||
|
(Added by Antoine Pitrou; :issue:`477863`.)
|
||||||
|
|
||||||
* The :func:`shutil.copytree` function has two new options:
|
* The :func:`shutil.copytree` function has two new options:
|
||||||
|
|
||||||
* *ignore_dangling_symlinks*: when ``symlinks=False`` (meaning that the
|
* *ignore_dangling_symlinks*: when ``symlinks=False`` (meaning that the
|
||||||
|
|
|
@ -148,6 +148,7 @@ PyAPI_FUNC(void) PyBytes_Fini(void);
|
||||||
PyAPI_FUNC(void) PyByteArray_Fini(void);
|
PyAPI_FUNC(void) PyByteArray_Fini(void);
|
||||||
PyAPI_FUNC(void) PyFloat_Fini(void);
|
PyAPI_FUNC(void) PyFloat_Fini(void);
|
||||||
PyAPI_FUNC(void) PyOS_FiniInterrupts(void);
|
PyAPI_FUNC(void) PyOS_FiniInterrupts(void);
|
||||||
|
PyAPI_FUNC(void) _PyGC_Fini(void);
|
||||||
|
|
||||||
/* Stuff with no proper home (yet) */
|
/* Stuff with no proper home (yet) */
|
||||||
PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, char *);
|
PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, char *);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import unittest
|
import unittest
|
||||||
from test.support import verbose, run_unittest
|
from test.support import verbose, run_unittest, strip_python_stderr
|
||||||
import sys
|
import sys
|
||||||
import gc
|
import gc
|
||||||
import weakref
|
import weakref
|
||||||
|
@ -466,6 +466,42 @@ class GCTests(unittest.TestCase):
|
||||||
# would be damaged, with an empty __dict__.
|
# would be damaged, with an empty __dict__.
|
||||||
self.assertEqual(x, None)
|
self.assertEqual(x, None)
|
||||||
|
|
||||||
|
def test_garbage_at_shutdown(self):
|
||||||
|
import subprocess
|
||||||
|
code = """if 1:
|
||||||
|
import gc
|
||||||
|
class X:
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
def __repr__(self):
|
||||||
|
return "<X %%r>" %% self.name
|
||||||
|
def __del__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
x = X('first')
|
||||||
|
x.x = x
|
||||||
|
x.y = X('second')
|
||||||
|
del x
|
||||||
|
if %d:
|
||||||
|
gc.set_debug(gc.DEBUG_UNCOLLECTABLE)
|
||||||
|
"""
|
||||||
|
def run_command(code):
|
||||||
|
p = subprocess.Popen([sys.executable, "-c", code],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE)
|
||||||
|
stdout, stderr = p.communicate()
|
||||||
|
self.assertEqual(p.returncode, 0)
|
||||||
|
self.assertEqual(stdout.strip(), b"")
|
||||||
|
return strip_python_stderr(stderr)
|
||||||
|
|
||||||
|
stderr = run_command(code % 0)
|
||||||
|
self.assertIn(b"gc: 2 uncollectable objects at shutdown", stderr)
|
||||||
|
self.assertNotIn(b"[<X 'first'>, <X 'second'>]", stderr)
|
||||||
|
# With DEBUG_UNCOLLECTABLE, the garbage list gets printed
|
||||||
|
stderr = run_command(code % 1)
|
||||||
|
self.assertIn(b"gc: 2 uncollectable objects at shutdown", stderr)
|
||||||
|
self.assertIn(b"[<X 'first'>, <X 'second'>]", stderr)
|
||||||
|
|
||||||
class GCTogglingTests(unittest.TestCase):
|
class GCTogglingTests(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
gc.enable()
|
gc.enable()
|
||||||
|
|
|
@ -30,6 +30,8 @@ Core and Builtins
|
||||||
Extensions
|
Extensions
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
- Issue #477863: Print a warning at shutdown if gc.garbage is not empty.
|
||||||
|
|
||||||
- Issue #6869: Fix a refcount problem in the _ctypes extension.
|
- Issue #6869: Fix a refcount problem in the _ctypes extension.
|
||||||
|
|
||||||
- Issue #5504: ctypes should now work with systems where mmap can't
|
- Issue #5504: ctypes should now work with systems where mmap can't
|
||||||
|
|
|
@ -1295,17 +1295,16 @@ static PyMethodDef GcMethods[] = {
|
||||||
|
|
||||||
static struct PyModuleDef gcmodule = {
|
static struct PyModuleDef gcmodule = {
|
||||||
PyModuleDef_HEAD_INIT,
|
PyModuleDef_HEAD_INIT,
|
||||||
"gc",
|
"gc", /* m_name */
|
||||||
gc__doc__,
|
gc__doc__, /* m_doc */
|
||||||
-1,
|
-1, /* m_size */
|
||||||
GcMethods,
|
GcMethods, /* m_methods */
|
||||||
NULL,
|
NULL, /* m_reload */
|
||||||
NULL,
|
NULL, /* m_traverse */
|
||||||
NULL,
|
NULL, /* m_clear */
|
||||||
NULL
|
NULL /* m_free */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
PyInit_gc(void)
|
PyInit_gc(void)
|
||||||
{
|
{
|
||||||
|
@ -1364,6 +1363,37 @@ PyGC_Collect(void)
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_PyGC_Fini(void)
|
||||||
|
{
|
||||||
|
if (garbage != NULL && PyList_GET_SIZE(garbage) > 0) {
|
||||||
|
PySys_WriteStderr(
|
||||||
|
"gc: "
|
||||||
|
"%" PY_FORMAT_SIZE_T "d uncollectable objects at shutdown:\n",
|
||||||
|
PyList_GET_SIZE(garbage)
|
||||||
|
);
|
||||||
|
if (debug & DEBUG_UNCOLLECTABLE) {
|
||||||
|
PyObject *repr = NULL, *bytes = NULL;
|
||||||
|
repr = PyObject_Repr(garbage);
|
||||||
|
if (!repr || !(bytes = PyUnicode_EncodeFSDefault(repr)))
|
||||||
|
PyErr_WriteUnraisable(garbage);
|
||||||
|
else {
|
||||||
|
PySys_WriteStderr(
|
||||||
|
" %s\n",
|
||||||
|
PyBytes_AS_STRING(bytes)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Py_XDECREF(repr);
|
||||||
|
Py_XDECREF(bytes);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PySys_WriteStderr(
|
||||||
|
" Use gc.set_debug(gc.DEBUG_UNCOLLECTABLE) to list them.\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* for debugging */
|
/* for debugging */
|
||||||
void
|
void
|
||||||
_PyGC_Dump(PyGC_Head *g)
|
_PyGC_Dump(PyGC_Head *g)
|
||||||
|
|
|
@ -404,6 +404,9 @@ Py_Finalize(void)
|
||||||
while (PyGC_Collect() > 0)
|
while (PyGC_Collect() > 0)
|
||||||
/* nothing */;
|
/* nothing */;
|
||||||
#endif
|
#endif
|
||||||
|
/* We run this while most interpreter state is still alive, so that
|
||||||
|
debug information can be printed out */
|
||||||
|
_PyGC_Fini();
|
||||||
|
|
||||||
/* Destroy all modules */
|
/* Destroy all modules */
|
||||||
PyImport_Cleanup();
|
PyImport_Cleanup();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue