| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -217,6 +217,7 @@ PyAPI_FUNC(void) PyBytes_Fini(void); | |||
| 217 | 217 | PyAPI_FUNC(void) PyByteArray_Fini(void); | |
| 218 | 218 | PyAPI_FUNC(void) PyFloat_Fini(void); | |
| 219 | 219 | PyAPI_FUNC(void) PyOS_FiniInterrupts(void); | |
| 220 | + PyAPI_FUNC(void) _PyGC_DumpShutdownStats(void); | ||
| 220 | 221 | PyAPI_FUNC(void) _PyGC_Fini(void); | |
| 221 | 222 | PyAPI_FUNC(void) PySlice_Fini(void); | |
| 222 | 223 | PyAPI_FUNC(void) _PyType_Fini(void); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,8 @@ | |||
| 1 | 1 | import unittest | |
| 2 | 2 | from test.support import (verbose, refcount_test, run_unittest, | |
| 3 | 3 | strip_python_stderr) | |
| 4 | + from test.script_helper import assert_python_ok, make_script, temp_dir | ||
| 5 | + | ||
| 4 | 6 | import sys | |
| 5 | 7 | import time | |
| 6 | 8 | import gc | |
@@ -610,6 +612,40 @@ def run_command(code): | |||
| 610 | 612 | stderr = run_command(code % "gc.DEBUG_SAVEALL") | |
| 611 | 613 | self.assertNotIn(b"uncollectable objects at shutdown", stderr) | |
| 612 | 614 | ||
| 615 | + def test_gc_main_module_at_shutdown(self): | ||
| 616 | + # Create a reference cycle through the __main__ module and check | ||
| 617 | + # it gets collected at interpreter shutdown. | ||
| 618 | + code = """if 1: | ||
| 619 | + import weakref | ||
| 620 | + class C: | ||
| 621 | + def __del__(self): | ||
| 622 | + print('__del__ called') | ||
| 623 | + l = [C()] | ||
| 624 | + l.append(l) | ||
| 625 | + """ | ||
| 626 | + rc, out, err = assert_python_ok('-c', code) | ||
| 627 | + self.assertEqual(out.strip(), b'__del__ called') | ||
| 628 | + | ||
| 629 | + def test_gc_ordinary_module_at_shutdown(self): | ||
| 630 | + # Same as above, but with a non-__main__ module. | ||
| 631 | + with temp_dir() as script_dir: | ||
| 632 | + module = """if 1: | ||
| 633 | + import weakref | ||
| 634 | + class C: | ||
| 635 | + def __del__(self): | ||
| 636 | + print('__del__ called') | ||
| 637 | + l = [C()] | ||
| 638 | + l.append(l) | ||
| 639 | + """ | ||
| 640 | + code = """if 1: | ||
| 641 | + import sys | ||
| 642 | + sys.path.insert(0, %r) | ||
| 643 | + import gctest | ||
| 644 | + """ % (script_dir,) | ||
| 645 | + make_script(script_dir, 'gctest', module) | ||
| 646 | + rc, out, err = assert_python_ok('-c', code) | ||
| 647 | + self.assertEqual(out.strip(), b'__del__ called') | ||
| 648 | + | ||
| 613 | 649 | def test_get_stats(self): | |
| 614 | 650 | stats = gc.get_stats() | |
| 615 | 651 | self.assertEqual(len(stats), 3) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1? | |||
| 10 | 10 | Core and Builtins | |
| 11 | 11 | ----------------- | |
| 12 | 12 | ||
| 13 | + - Issue #1545463: Global variables caught in reference cycles are now | ||
| 14 | + garbage-collected at shutdown. | ||
| 15 | + | ||
| 13 | 16 | - Issue #17094: Clear stale thread states after fork(). Note that this | |
| 14 | 17 | is a potentially disruptive change since it may release some system | |
| 15 | 18 | resources which would otherwise remain perpetually alive (e.g. database | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1544,8 +1544,9 @@ PyGC_Collect(void) | |||
| 1544 | 1544 | return n; | |
| 1545 | 1545 | } | |
| 1546 | 1546 | ||
| 1547 | + | ||
| 1547 | 1548 | void | |
| 1548 | - _PyGC_Fini(void) | ||
| 1549 | + _PyGC_DumpShutdownStats(void) | ||
| 1549 | 1550 | { | |
| 1550 | 1551 | if (!(debug & DEBUG_SAVEALL) | |
| 1551 | 1552 | && garbage != NULL && PyList_GET_SIZE(garbage) > 0) { | |
@@ -1574,6 +1575,11 @@ _PyGC_Fini(void) | |||
| 1574 | 1575 | Py_XDECREF(bytes); | |
| 1575 | 1576 | } | |
| 1576 | 1577 | } | |
| 1578 | + } | ||
| 1579 | + | ||
| 1580 | + void | ||
| 1581 | + _PyGC_Fini(void) | ||
| 1582 | + { | ||
| 1577 | 1583 | Py_CLEAR(callbacks); | |
| 1578 | 1584 | } | |
| 1579 | 1585 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -403,6 +403,14 @@ PyImport_Cleanup(void) | |||
| 403 | 403 | } | |
| 404 | 404 | } | |
| 405 | 405 | ||
| 406 | + /* Collect garbage remaining after deleting the modules. Mostly | ||
| 407 | + reference cycles created by classes. */ | ||
| 408 | + PyGC_Collect(); | ||
| 409 | + | ||
| 410 | + /* Dump GC stats before it's too late, since it uses the warnings | ||
| 411 | + machinery. */ | ||
| 412 | + _PyGC_DumpShutdownStats(); | ||
| 413 | + | ||
| 406 | 414 | /* Next, delete sys and builtins (in that order) */ | |
| 407 | 415 | value = PyDict_GetItemString(modules, "sys"); | |
| 408 | 416 | if (value != NULL && PyModule_Check(value)) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -544,10 +544,6 @@ Py_Finalize(void) | |||
| 544 | 544 | while (PyGC_Collect() > 0) | |
| 545 | 545 | /* nothing */; | |
| 546 | 546 | #endif | |
| 547 | - /* We run this while most interpreter state is still alive, so that | ||
| 548 | - debug information can be printed out */ | ||
| 549 | - _PyGC_Fini(); | ||
| 550 | - | ||
| 551 | 547 | /* Destroy all modules */ | |
| 552 | 548 | PyImport_Cleanup(); | |
| 553 | 549 | ||
@@ -628,6 +624,7 @@ Py_Finalize(void) | |||
| 628 | 624 | PyFloat_Fini(); | |
| 629 | 625 | PyDict_Fini(); | |
| 630 | 626 | PySlice_Fini(); | |
| 627 | + _PyGC_Fini(); | ||
| 631 | 628 | ||
| 632 | 629 | /* Cleanup Unicode implementation */ | |
| 633 | 630 | _PyUnicode_Fini(); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments