[3.14] GH-139951: Fix major GC performance regression. Backport of GH-140262 (GH-140447)

* Count number of actually tracked objects, instead of trackable objects. This ensures that untracking tuples has the desired effect of reducing GC overhead
* Do not track most untrackable tuples during creation. This prevents large numbers of small tuples causing execessive GCs.
This commit is contained in:
Mark Shannon 2025-10-23 15:26:58 +01:00 committed by GitHub
parent 0fdae5f590
commit d1a434f7b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 94 additions and 36 deletions

View file

@ -1329,6 +1329,7 @@ def setUp(self):
def tearDown(self):
gc.disable()
@unittest.skipIf(Py_GIL_DISABLED, "requires GC generations or increments")
def test_bug1055820c(self):
# Corresponds to temp2c.py in the bug report. This is pretty
# elaborate.
@ -1390,10 +1391,11 @@ def callback(ignored):
# The free-threaded build doesn't have multiple generations, so
# just trigger a GC manually.
gc.collect()
assert not detector.gc_happened
while not detector.gc_happened:
i += 1
if i > 10000:
self.fail("gc didn't happen after 10000 iterations")
if i > 100000:
self.fail("gc didn't happen after 100000 iterations")
self.assertEqual(len(ouch), 0)
junk.append([]) # this will eventually trigger gc
@ -1464,8 +1466,8 @@ def __del__(self):
gc.collect()
while not detector.gc_happened:
i += 1
if i > 10000:
self.fail("gc didn't happen after 10000 iterations")
if i > 50000:
self.fail("gc didn't happen after 50000 iterations")
self.assertEqual(len(ouch), 0)
junk.append([]) # this will eventually trigger gc
@ -1482,8 +1484,8 @@ def test_indirect_calls_with_gc_disabled(self):
detector = GC_Detector()
while not detector.gc_happened:
i += 1
if i > 10000:
self.fail("gc didn't happen after 10000 iterations")
if i > 100000:
self.fail("gc didn't happen after 100000 iterations")
junk.append([]) # this will eventually trigger gc
try:
@ -1493,11 +1495,11 @@ def test_indirect_calls_with_gc_disabled(self):
detector = GC_Detector()
while not detector.gc_happened:
i += 1
if i > 10000:
if i > 100000:
break
junk.append([]) # this may eventually trigger gc (if it is enabled)
self.assertEqual(i, 10001)
self.assertEqual(i, 100001)
finally:
gc.enable()