Kaydet (Commit) 5f454a07 authored tarafından Antoine Pitrou's avatar Antoine Pitrou

Issue #1545463: Global variables caught in reference cycles are now garbage-collected at shutdown.

üst 1df37c65
...@@ -217,6 +217,7 @@ PyAPI_FUNC(void) PyBytes_Fini(void); ...@@ -217,6 +217,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_DumpShutdownStats(void);
PyAPI_FUNC(void) _PyGC_Fini(void); PyAPI_FUNC(void) _PyGC_Fini(void);
PyAPI_FUNC(void) PySlice_Fini(void); PyAPI_FUNC(void) PySlice_Fini(void);
PyAPI_FUNC(void) _PyType_Fini(void); PyAPI_FUNC(void) _PyType_Fini(void);
......
import unittest import unittest
from test.support import (verbose, refcount_test, run_unittest, from test.support import (verbose, refcount_test, run_unittest,
strip_python_stderr) strip_python_stderr)
from test.script_helper import assert_python_ok, make_script, temp_dir
import sys import sys
import time import time
import gc import gc
...@@ -610,6 +612,40 @@ class GCTests(unittest.TestCase): ...@@ -610,6 +612,40 @@ class GCTests(unittest.TestCase):
stderr = run_command(code % "gc.DEBUG_SAVEALL") stderr = run_command(code % "gc.DEBUG_SAVEALL")
self.assertNotIn(b"uncollectable objects at shutdown", stderr) self.assertNotIn(b"uncollectable objects at shutdown", stderr)
def test_gc_main_module_at_shutdown(self):
# Create a reference cycle through the __main__ module and check
# it gets collected at interpreter shutdown.
code = """if 1:
import weakref
class C:
def __del__(self):
print('__del__ called')
l = [C()]
l.append(l)
"""
rc, out, err = assert_python_ok('-c', code)
self.assertEqual(out.strip(), b'__del__ called')
def test_gc_ordinary_module_at_shutdown(self):
# Same as above, but with a non-__main__ module.
with temp_dir() as script_dir:
module = """if 1:
import weakref
class C:
def __del__(self):
print('__del__ called')
l = [C()]
l.append(l)
"""
code = """if 1:
import sys
sys.path.insert(0, %r)
import gctest
""" % (script_dir,)
make_script(script_dir, 'gctest', module)
rc, out, err = assert_python_ok('-c', code)
self.assertEqual(out.strip(), b'__del__ called')
def test_get_stats(self): def test_get_stats(self):
stats = gc.get_stats() stats = gc.get_stats()
self.assertEqual(len(stats), 3) self.assertEqual(len(stats), 3)
......
...@@ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1? ...@@ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1?
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #1545463: Global variables caught in reference cycles are now
garbage-collected at shutdown.
- Issue #17094: Clear stale thread states after fork(). Note that this - Issue #17094: Clear stale thread states after fork(). Note that this
is a potentially disruptive change since it may release some system is a potentially disruptive change since it may release some system
resources which would otherwise remain perpetually alive (e.g. database resources which would otherwise remain perpetually alive (e.g. database
......
...@@ -1544,8 +1544,9 @@ PyGC_Collect(void) ...@@ -1544,8 +1544,9 @@ PyGC_Collect(void)
return n; return n;
} }
void void
_PyGC_Fini(void) _PyGC_DumpShutdownStats(void)
{ {
if (!(debug & DEBUG_SAVEALL) if (!(debug & DEBUG_SAVEALL)
&& garbage != NULL && PyList_GET_SIZE(garbage) > 0) { && garbage != NULL && PyList_GET_SIZE(garbage) > 0) {
...@@ -1574,6 +1575,11 @@ _PyGC_Fini(void) ...@@ -1574,6 +1575,11 @@ _PyGC_Fini(void)
Py_XDECREF(bytes); Py_XDECREF(bytes);
} }
} }
}
void
_PyGC_Fini(void)
{
Py_CLEAR(callbacks); Py_CLEAR(callbacks);
} }
......
...@@ -403,6 +403,14 @@ PyImport_Cleanup(void) ...@@ -403,6 +403,14 @@ PyImport_Cleanup(void)
} }
} }
/* Collect garbage remaining after deleting the modules. Mostly
reference cycles created by classes. */
PyGC_Collect();
/* Dump GC stats before it's too late, since it uses the warnings
machinery. */
_PyGC_DumpShutdownStats();
/* Next, delete sys and builtins (in that order) */ /* Next, delete sys and builtins (in that order) */
value = PyDict_GetItemString(modules, "sys"); value = PyDict_GetItemString(modules, "sys");
if (value != NULL && PyModule_Check(value)) { if (value != NULL && PyModule_Check(value)) {
......
...@@ -544,10 +544,6 @@ Py_Finalize(void) ...@@ -544,10 +544,6 @@ 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();
...@@ -628,6 +624,7 @@ Py_Finalize(void) ...@@ -628,6 +624,7 @@ Py_Finalize(void)
PyFloat_Fini(); PyFloat_Fini();
PyDict_Fini(); PyDict_Fini();
PySlice_Fini(); PySlice_Fini();
_PyGC_Fini();
/* Cleanup Unicode implementation */ /* Cleanup Unicode implementation */
_PyUnicode_Fini(); _PyUnicode_Fini();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment