Skip to content

Commit 86ae540

Browse files
committed
gh-159137: Skip redundant GC resurrection analysis
1 parent 565f76f commit 86ae540

2 files changed

Lines changed: 23 additions & 5 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Avoid a second reachability analysis in the garbage collector when no weakref
2+
callback, finalizer, or collectable-object debug output ran.

‎Python/gc.c‎

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,8 @@ move_legacy_finalizer_reachable(PyGC_Head *finalizers)
805805
* Python-level code. See bpo-38006 as an example bug.
806806
*/
807807
static int
808-
handle_weakref_callbacks(PyGC_Head *unreachable, PyGC_Head *old)
808+
handle_weakref_callbacks(PyGC_Head *unreachable, PyGC_Head *old,
809+
bool *needs_resurrection_check)
809810
{
810811
PyGC_Head *gc;
811812
PyGC_Head wrcb_to_call; /* weakrefs with callbacks to call */
@@ -917,6 +918,7 @@ handle_weakref_callbacks(PyGC_Head *unreachable, PyGC_Head *old)
917918
callback = wr->wr_callback;
918919
_PyObject_ASSERT(op, callback != NULL);
919920

921+
*needs_resurrection_check = true;
920922
/* copy-paste of weakrefobject.c's handle_callback() */
921923
temp = PyObject_CallOneArg(callback, (PyObject *)wr);
922924
if (temp == NULL) {
@@ -1043,7 +1045,8 @@ handle_legacy_finalizers(PyThreadState *tstate,
10431045
* list, due to refcounts falling to 0.
10441046
*/
10451047
static void
1046-
finalize_garbage(PyThreadState *tstate, PyGC_Head *collectable)
1048+
finalize_garbage(PyThreadState *tstate, PyGC_Head *collectable,
1049+
bool *needs_resurrection_check)
10471050
{
10481051
destructor finalize;
10491052
PyGC_Head seen;
@@ -1065,6 +1068,7 @@ finalize_garbage(PyThreadState *tstate, PyGC_Head *collectable)
10651068
if (!_PyGC_FINALIZED(op) &&
10661069
(finalize = Py_TYPE(op)->tp_finalize) != NULL)
10671070
{
1071+
*needs_resurrection_check = true;
10681072
_PyGC_SET_FINALIZED(op);
10691073
Py_INCREF(op);
10701074
finalize(op);
@@ -1550,26 +1554,38 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason)
15501554
validate_list(&finalizers, collecting_clear_unreachable_clear);
15511555
validate_list(&unreachable, collecting_set_unreachable_clear);
15521556

1557+
bool needs_resurrection_check = false;
1558+
15531559
/* Print debugging information. */
15541560
if (gcstate->debug & _PyGC_DEBUG_COLLECTABLE) {
1561+
/* sys.stderr.write() can resurrect objects. */
1562+
needs_resurrection_check = true;
15551563
for (gc = GC_NEXT(&unreachable); gc != &unreachable; gc = GC_NEXT(gc)) {
15561564
debug_cycle("collectable", FROM_GC(gc));
15571565
}
15581566
}
15591567

15601568
/* Clear weakrefs and invoke callbacks as necessary. */
1561-
stats.collected += handle_weakref_callbacks(&unreachable, old);
1569+
stats.collected += handle_weakref_callbacks(&unreachable, old,
1570+
&needs_resurrection_check);
15621571
validate_list(old, collecting_clear_unreachable_clear);
15631572
validate_list(&unreachable, collecting_set_unreachable_clear);
15641573

15651574
/* Call tp_finalize on objects which have one. */
1566-
finalize_garbage(tstate, &unreachable);
1575+
finalize_garbage(tstate, &unreachable, &needs_resurrection_check);
15671576

15681577
/* Handle any objects that may have resurrected after the call
15691578
* to 'finalize_garbage' and continue the collection with the
15701579
* objects that are still unreachable */
15711580
PyGC_Head final_unreachable;
1572-
handle_resurrected_objects(&unreachable, &final_unreachable, old);
1581+
if (needs_resurrection_check) {
1582+
handle_resurrected_objects(&unreachable, &final_unreachable, old);
1583+
}
1584+
else {
1585+
/* No callbacks ran, so the original unreachable set is still valid. */
1586+
gc_list_init(&final_unreachable);
1587+
gc_list_merge(&unreachable, &final_unreachable);
1588+
}
15731589

15741590
/* Clear weakrefs to objects in the unreachable set. No Python-level
15751591
* code must be allowed to access those unreachable objects. During

0 commit comments

Comments
 (0)