diff options
author | Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> | 2024-11-19 09:25:09 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-19 09:25:09 (GMT) |
commit | 899fdb213db6c5881c5f9c6760ead6fd713d2070 (patch) | |
tree | c4e291504c73e8055d02176551beeb39ab47e6ad /Lib/test | |
parent | 84f07c3a4cbcfe488ccfb4030571be0bc4de7e45 (diff) | |
download | cpython-899fdb213db6c5881c5f9c6760ead6fd713d2070.zip cpython-899fdb213db6c5881c5f9c6760ead6fd713d2070.tar.gz cpython-899fdb213db6c5881c5f9c6760ead6fd713d2070.tar.bz2 |
Revert "GH-126491: GC: Mark objects reachable from roots before doing cycle collection (GH-126502)" (#126983)
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/test_dict.py | 109 | ||||
-rw-r--r-- | Lib/test/test_gc.py | 33 |
2 files changed, 128 insertions, 14 deletions
diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index c94dc2d..4030716 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -880,6 +880,115 @@ class DictTest(unittest.TestCase): gc.collect() self.assertIs(ref(), None, "Cycle was not collected") + def _not_tracked(self, t): + # Nested containers can take several collections to untrack + gc.collect() + gc.collect() + self.assertFalse(gc.is_tracked(t), t) + + def _tracked(self, t): + self.assertTrue(gc.is_tracked(t), t) + gc.collect() + gc.collect() + self.assertTrue(gc.is_tracked(t), t) + + def test_string_keys_can_track_values(self): + # Test that this doesn't leak. + for i in range(10): + d = {} + for j in range(10): + d[str(j)] = j + d["foo"] = d + + @support.cpython_only + def test_track_literals(self): + # Test GC-optimization of dict literals + x, y, z, w = 1.5, "a", (1, None), [] + + self._not_tracked({}) + self._not_tracked({x:(), y:x, z:1}) + self._not_tracked({1: "a", "b": 2}) + self._not_tracked({1: 2, (None, True, False, ()): int}) + self._not_tracked({1: object()}) + + # Dicts with mutable elements are always tracked, even if those + # elements are not tracked right now. + self._tracked({1: []}) + self._tracked({1: ([],)}) + self._tracked({1: {}}) + self._tracked({1: set()}) + + @support.cpython_only + def test_track_dynamic(self): + # Test GC-optimization of dynamically-created dicts + class MyObject(object): + pass + x, y, z, w, o = 1.5, "a", (1, object()), [], MyObject() + + d = dict() + self._not_tracked(d) + d[1] = "a" + self._not_tracked(d) + d[y] = 2 + self._not_tracked(d) + d[z] = 3 + self._not_tracked(d) + self._not_tracked(d.copy()) + d[4] = w + self._tracked(d) + self._tracked(d.copy()) + d[4] = None + self._not_tracked(d) + self._not_tracked(d.copy()) + + # dd isn't tracked right now, but it may mutate and therefore d + # which contains it must be tracked. + d = dict() + dd = dict() + d[1] = dd + self._not_tracked(dd) + self._tracked(d) + dd[1] = d + self._tracked(dd) + + d = dict.fromkeys([x, y, z]) + self._not_tracked(d) + dd = dict() + dd.update(d) + self._not_tracked(dd) + d = dict.fromkeys([x, y, z, o]) + self._tracked(d) + dd = dict() + dd.update(d) + self._tracked(dd) + + d = dict(x=x, y=y, z=z) + self._not_tracked(d) + d = dict(x=x, y=y, z=z, w=w) + self._tracked(d) + d = dict() + d.update(x=x, y=y, z=z) + self._not_tracked(d) + d.update(w=w) + self._tracked(d) + + d = dict([(x, y), (z, 1)]) + self._not_tracked(d) + d = dict([(x, y), (z, w)]) + self._tracked(d) + d = dict() + d.update([(x, y), (z, 1)]) + self._not_tracked(d) + d.update([(x, y), (z, w)]) + self._tracked(d) + + @support.cpython_only + def test_track_subtypes(self): + # Dict subtypes are always tracked + class MyDict(dict): + pass + self._tracked(MyDict()) + def make_shared_key_dict(self, n): class C: pass diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py index e02ec7c..0372815 100644 --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -31,11 +31,6 @@ except ImportError: return C ContainerNoGC = None -try: - import _testinternalcapi -except ImportError: - _testinternalcapi = None - ### Support code ############################################################################### @@ -1135,7 +1130,6 @@ class IncrementalGCTests(unittest.TestCase): def tearDown(self): gc.disable() - @unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi") @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) @@ -1161,18 +1155,32 @@ class IncrementalGCTests(unittest.TestCase): 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_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_heap_size() - initial_heap_size - self.assertLess(new_objects, 25_000) + stats = gc.get_stats() + young = stats[0] + incremental = stats[1] + old = stats[2] + collected = young['collected'] + incremental['collected'] + old['collected'] + count += CORRECTION + live = count - collected + self.assertLess(live, 25000) del olds[:] if not enabled: gc.disable() @@ -1314,8 +1322,7 @@ class GCCallbackTests(unittest.TestCase): from test.support import gc_collect, SuppressCrashReport a = [1, 2, 3] - b = [a, a] - a.append(b) + b = [a] # Avoid coredump when Py_FatalError() calls abort() SuppressCrashReport().__enter__() @@ -1325,8 +1332,6 @@ class GCCallbackTests(unittest.TestCase): # (to avoid deallocating it): import ctypes ctypes.pythonapi.Py_DecRef(ctypes.py_object(a)) - del a - del b # The garbage collector should now have a fatal error # when it reaches the broken object @@ -1355,7 +1360,7 @@ class GCCallbackTests(unittest.TestCase): self.assertRegex(stderr, br'object type name: list') self.assertRegex(stderr, - br'object repr : \[1, 2, 3, \[\[...\], \[...\]\]\]') + br'object repr : \[1, 2, 3\]') class GCTogglingTests(unittest.TestCase): |