mirror of
https://github.com/python/cpython.git
synced 2025-07-24 11:44:31 +00:00
GH-126491: GC: Mark objects reachable from roots before doing cycle collection (GH-126502)
* Mark almost all reachable objects before doing collection phase * Add stats for objects marked * Visit new frames before each increment * Remove lazy dict tracking * Update docs * Clearer calculation of work to do.
This commit is contained in:
parent
a1d9c8aa80
commit
b0fcc2c47a
21 changed files with 332 additions and 330 deletions
|
@ -31,6 +31,11 @@ except ImportError:
|
|||
return C
|
||||
ContainerNoGC = None
|
||||
|
||||
try:
|
||||
import _testinternalcapi
|
||||
except ImportError:
|
||||
_testinternalcapi = None
|
||||
|
||||
### Support code
|
||||
###############################################################################
|
||||
|
||||
|
@ -1130,6 +1135,7 @@ 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)
|
||||
|
@ -1155,32 +1161,18 @@ 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:
|
||||
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)
|
||||
new_objects = _testinternalcapi.get_heap_size() - initial_heap_size
|
||||
self.assertLess(new_objects, 25_000)
|
||||
del olds[:]
|
||||
if not enabled:
|
||||
gc.disable()
|
||||
|
@ -1322,7 +1314,8 @@ class GCCallbackTests(unittest.TestCase):
|
|||
from test.support import gc_collect, SuppressCrashReport
|
||||
|
||||
a = [1, 2, 3]
|
||||
b = [a]
|
||||
b = [a, a]
|
||||
a.append(b)
|
||||
|
||||
# Avoid coredump when Py_FatalError() calls abort()
|
||||
SuppressCrashReport().__enter__()
|
||||
|
@ -1332,6 +1325,8 @@ 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
|
||||
|
@ -1360,7 +1355,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):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue