[3.14] gh-133532: Run GC fast cycles test in subprocess. (gh-133533) (gh-133716)

This makes the test more reliable since there are not extra objects on the heap leftover
from other tests.

(cherry picked from commit 8598e57942)

Co-authored-by: Neil Schemenauer <nas-github@arctrix.com>
This commit is contained in:
Miss Islington (bot) 2025-05-09 21:30:27 +02:00 committed by GitHub
parent da41ce6b69
commit aaeca91b05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 54 additions and 56 deletions

View file

@ -0,0 +1,48 @@
# Run by test_gc.
from test import support
import _testinternalcapi
import gc
import unittest
class IncrementalGCTests(unittest.TestCase):
# Use small increments to emulate longer running process in a shorter time
@support.gc_threshold(200, 10)
def test_incremental_gc_handles_fast_cycle_creation(self):
class LinkedList:
#Use slots to reduce number of implicit objects
__slots__ = "next", "prev", "surprise"
def __init__(self, next=None, prev=None):
self.next = next
if next is not None:
next.prev = self
self.prev = prev
if prev is not None:
prev.next = self
def make_ll(depth):
head = LinkedList()
for i in range(depth):
head = LinkedList(head, head.prev)
return head
head = make_ll(1000)
assert(gc.isenabled())
olds = []
initial_heap_size = _testinternalcapi.get_tracked_heap_size()
for i in range(20_000):
newhead = make_ll(20)
newhead.surprise = head
olds.append(newhead)
if len(olds) == 20:
new_objects = _testinternalcapi.get_tracked_heap_size() - initial_heap_size
self.assertLess(new_objects, 27_000, f"Heap growing. Reached limit after {i} iterations")
del olds[:]
if __name__ == "__main__":
unittest.main()

View file

@ -7,7 +7,7 @@ from test.support import (verbose, refcount_test,
Py_GIL_DISABLED) Py_GIL_DISABLED)
from test.support.import_helper import import_module from test.support.import_helper import import_module
from test.support.os_helper import temp_dir, TESTFN, unlink from test.support.os_helper import temp_dir, TESTFN, unlink
from test.support.script_helper import assert_python_ok, make_script from test.support.script_helper import assert_python_ok, make_script, run_test_script
from test.support import threading_helper, gc_threshold from test.support import threading_helper, gc_threshold
import gc import gc
@ -1127,64 +1127,14 @@ class GCTests(unittest.TestCase):
class IncrementalGCTests(unittest.TestCase): class IncrementalGCTests(unittest.TestCase):
def setUp(self):
# Reenable GC as it is disabled module-wide
gc.enable()
def tearDown(self):
gc.disable()
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi") @unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
@requires_gil_enabled("Free threading does not support incremental GC") @requires_gil_enabled("Free threading does not support incremental GC")
# Use small increments to emulate longer running process in a shorter time
@gc_threshold(200, 10)
def test_incremental_gc_handles_fast_cycle_creation(self): def test_incremental_gc_handles_fast_cycle_creation(self):
# Run this test in a fresh process. The number of alive objects (which can
class LinkedList: # be from unit tests run before this one) can influence how quickly cyclic
# garbage is found.
#Use slots to reduce number of implicit objects script = support.findfile("_test_gc_fast_cycles.py")
__slots__ = "next", "prev", "surprise" run_test_script(script)
def __init__(self, next=None, prev=None):
self.next = next
if next is not None:
next.prev = self
self.prev = prev
if prev is not None:
prev.next = self
def make_ll(depth):
head = LinkedList()
for i in range(depth):
head = LinkedList(head, head.prev)
return head
head = make_ll(1000)
count = 1000
# There will be some objects we aren't counting,
# e.g. the gc stats dicts. This test checks
# that the counts don't grow, so we try to
# correct for the uncounted objects
# This is just an estimate.
CORRECTION = 20
enabled = gc.isenabled()
gc.enable()
olds = []
initial_heap_size = _testinternalcapi.get_tracked_heap_size()
for i in range(20_000):
newhead = make_ll(20)
count += 20
newhead.surprise = head
olds.append(newhead)
if len(olds) == 20:
new_objects = _testinternalcapi.get_tracked_heap_size() - initial_heap_size
self.assertLess(new_objects, 27_000, f"Heap growing. Reached limit after {i} iterations")
del olds[:]
if not enabled:
gc.disable()
class GCCallbackTests(unittest.TestCase): class GCCallbackTests(unittest.TestCase):