Issue #17937: Try harder to collect cyclic garbage at shutdown.

This commit is contained in:
Antoine Pitrou 2013-05-19 01:11:58 +02:00
parent 20c1cdd64a
commit fef34e3186
4 changed files with 32 additions and 6 deletions

View File

@ -232,6 +232,10 @@ PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t);
/* C equivalent of gc.collect(). */
PyAPI_FUNC(Py_ssize_t) PyGC_Collect(void);
#ifndef Py_LIMITED_API
PyAPI_FUNC(Py_ssize_t) _PyGC_CollectNoFail(void);
#endif
/* Test if a type has a GC head */
#define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC)

View File

@ -10,6 +10,8 @@ What's New in Python 3.4.0 Alpha 1?
Core and Builtins
-----------------
- Issue #17937: Try harder to collect cyclic garbage at shutdown.
- Issue #12370: Prevent class bodies from interfering with the __class__
closure.

View File

@ -853,7 +853,8 @@ get_time(void)
/* This is the main function. Read this to understand how the
* collection process works. */
static Py_ssize_t
collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable)
collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable,
int nofail)
{
int i;
Py_ssize_t m = 0; /* # objects collected */
@ -1000,11 +1001,16 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable)
}
if (PyErr_Occurred()) {
if (nofail) {
PyErr_Clear();
}
else {
if (gc_str == NULL)
gc_str = PyUnicode_FromString("garbage collection");
PyErr_WriteUnraisable(gc_str);
Py_FatalError("unexpected exception during garbage collection");
}
}
/* Update stats */
if (n_collected)
@ -1062,7 +1068,7 @@ collect_with_callback(int generation)
{
Py_ssize_t result, collected, uncollectable;
invoke_gc_callback("start", generation, 0, 0);
result = collect(generation, &collected, &uncollectable);
result = collect(generation, &collected, &uncollectable, 0);
invoke_gc_callback("stop", generation, collected, uncollectable);
return result;
}
@ -1544,6 +1550,19 @@ PyGC_Collect(void)
return n;
}
Py_ssize_t
_PyGC_CollectNoFail(void)
{
Py_ssize_t n;
/* This function should only be called on interpreter shutdown, and
therefore not recursively. */
assert(!collecting);
collecting = 1;
n = collect(NUM_GENERATIONS - 1, NULL, NULL, 1);
collecting = 0;
return n;
}
void
_PyGC_DumpShutdownStats(void)

View File

@ -444,6 +444,7 @@ PyImport_Cleanup(void)
/* Finally, clear and delete the modules directory */
PyDict_Clear(modules);
_PyGC_CollectNoFail();
interp->modules = NULL;
Py_DECREF(modules);
}