Skip to content

Commit aaeca91

Browse files
[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 8598e57) Co-authored-by: Neil Schemenauer <nas-github@arctrix.com>
1 parent da41ce6 commit aaeca91

File tree

2 files changed

+54
-56
lines changed

2 files changed

+54
-56
lines changed

Lib/test/_test_gc_fast_cycles.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Run by test_gc.
2+
from test import support
3+
import _testinternalcapi
4+
import gc
5+
import unittest
6+
7+
class IncrementalGCTests(unittest.TestCase):
8+
9+
# Use small increments to emulate longer running process in a shorter time
10+
@support.gc_threshold(200, 10)
11+
def test_incremental_gc_handles_fast_cycle_creation(self):
12+
13+
class LinkedList:
14+
15+
#Use slots to reduce number of implicit objects
16+
__slots__ = "next", "prev", "surprise"
17+
18+
def __init__(self, next=None, prev=None):
19+
self.next = next
20+
if next is not None:
21+
next.prev = self
22+
self.prev = prev
23+
if prev is not None:
24+
prev.next = self
25+
26+
def make_ll(depth):
27+
head = LinkedList()
28+
for i in range(depth):
29+
head = LinkedList(head, head.prev)
30+
return head
31+
32+
head = make_ll(1000)
33+
34+
assert(gc.isenabled())
35+
olds = []
36+
initial_heap_size = _testinternalcapi.get_tracked_heap_size()
37+
for i in range(20_000):
38+
newhead = make_ll(20)
39+
newhead.surprise = head
40+
olds.append(newhead)
41+
if len(olds) == 20:
42+
new_objects = _testinternalcapi.get_tracked_heap_size() - initial_heap_size
43+
self.assertLess(new_objects, 27_000, f"Heap growing. Reached limit after {i} iterations")
44+
del olds[:]
45+
46+
47+
if __name__ == "__main__":
48+
unittest.main()

Lib/test/test_gc.py

Lines changed: 6 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
Py_GIL_DISABLED)
88
from test.support.import_helper import import_module
99
from test.support.os_helper import temp_dir, TESTFN, unlink
10-
from test.support.script_helper import assert_python_ok, make_script
10+
from test.support.script_helper import assert_python_ok, make_script, run_test_script
1111
from test.support import threading_helper, gc_threshold
1212

1313
import gc
@@ -1127,64 +1127,14 @@ def test_something(self):
11271127

11281128

11291129
class IncrementalGCTests(unittest.TestCase):
1130-
1131-
def setUp(self):
1132-
# Reenable GC as it is disabled module-wide
1133-
gc.enable()
1134-
1135-
def tearDown(self):
1136-
gc.disable()
1137-
11381130
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
11391131
@requires_gil_enabled("Free threading does not support incremental GC")
1140-
# Use small increments to emulate longer running process in a shorter time
1141-
@gc_threshold(200, 10)
11421132
def test_incremental_gc_handles_fast_cycle_creation(self):
1143-
1144-
class LinkedList:
1145-
1146-
#Use slots to reduce number of implicit objects
1147-
__slots__ = "next", "prev", "surprise"
1148-
1149-
def __init__(self, next=None, prev=None):
1150-
self.next = next
1151-
if next is not None:
1152-
next.prev = self
1153-
self.prev = prev
1154-
if prev is not None:
1155-
prev.next = self
1156-
1157-
def make_ll(depth):
1158-
head = LinkedList()
1159-
for i in range(depth):
1160-
head = LinkedList(head, head.prev)
1161-
return head
1162-
1163-
head = make_ll(1000)
1164-
count = 1000
1165-
1166-
# There will be some objects we aren't counting,
1167-
# e.g. the gc stats dicts. This test checks
1168-
# that the counts don't grow, so we try to
1169-
# correct for the uncounted objects
1170-
# This is just an estimate.
1171-
CORRECTION = 20
1172-
1173-
enabled = gc.isenabled()
1174-
gc.enable()
1175-
olds = []
1176-
initial_heap_size = _testinternalcapi.get_tracked_heap_size()
1177-
for i in range(20_000):
1178-
newhead = make_ll(20)
1179-
count += 20
1180-
newhead.surprise = head
1181-
olds.append(newhead)
1182-
if len(olds) == 20:
1183-
new_objects = _testinternalcapi.get_tracked_heap_size() - initial_heap_size
1184-
self.assertLess(new_objects, 27_000, f"Heap growing. Reached limit after {i} iterations")
1185-
del olds[:]
1186-
if not enabled:
1187-
gc.disable()
1133+
# Run this test in a fresh process. The number of alive objects (which can
1134+
# be from unit tests run before this one) can influence how quickly cyclic
1135+
# garbage is found.
1136+
script = support.findfile("_test_gc_fast_cycles.py")
1137+
run_test_script(script)
11881138

11891139

11901140
class GCCallbackTests(unittest.TestCase):

0 commit comments

Comments
 (0)