Skip to content

Commit 30bcedf

Browse files
naschemesergey-miryanov
authored andcommitted
Add notes about untrack_dicts() change.
1 parent e371a77 commit 30bcedf

File tree

2 files changed

+15
-4
lines changed

2 files changed

+15
-4
lines changed

InternalDocs/garbage_collector.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,14 @@ tuples can be untracked. A tuple can be untracked if all of its contents are
702702
already not tracked. Tuples are examined for untracking in all garbage collection
703703
cycles.
704704

705+
Dictionaries are always tracked from creation and are not untracked by the
706+
garbage collector. Earlier versions (up to 3.13) used lazy tracking: empty or
707+
atomic-only dicts were untracked on creation and re-tracked when a trackable
708+
value was inserted (via `MAINTAIN_TRACKING`), and full collections called
709+
`_PyDict_MaybeUntrack` to prune dicts whose values had become atomic. That
710+
machinery was removed in 3.14 (GH-127010) because the per-set-item cost of
711+
checking the tracking invariant outweighed the savings on full collections.
712+
705713
The garbage collector module provides the Python function `is_tracked(obj)`, which returns
706714
the current tracking status of the object. Subsequent garbage collections may change the
707715
tracking status of the object.

Python/gc.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,10 +1510,13 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason)
15101510
gc_list_merge(young, old);
15111511
}
15121512
else {
1513-
/* We only un-track dicts in full collections, to avoid quadratic
1514-
dict build-up. See issue #14775.
1515-
Note: _PyDict_MaybeUntrack was removed in 3.14, so dict
1516-
untracking during GC is no longer done. */
1513+
// In Python <= 3.13, we called untrack_dicts(young) here to untrack
1514+
// atomic-only dicts (see issue #14775). Python 3.14 removed the lazy
1515+
// dict tracking machinery entirely (GH-127010) -- dicts are always
1516+
// tracked from creation and never untracked by GC. That way, we don't
1517+
// have to restore MAINTAIN_TRACKING across every PyDict_SetItem call
1518+
// site; the cost is slightly more work for full collections on dicts
1519+
// with only atomic values.
15171520
gcstate->long_lived_pending = 0;
15181521
gcstate->long_lived_total = gc_list_size(young);
15191522
}

0 commit comments

Comments
 (0)