blob: caf5a3d0f96bef18f8bcd231cffab48501fe0483 [file] [log] [blame]
Guido van Rossumd8faa362007-04-27 19:54:29 +00001import unittest
Brett Cannon7a540732011-02-22 03:04:06 +00002from test.support import (verbose, refcount_test, run_unittest,
3 strip_python_stderr)
Neil Schemenauer88c761a2001-07-12 13:25:53 +00004import sys
Jeremy Hyltonc5007aa2000-06-30 05:02:53 +00005import gc
Tim Petersead8b7a2004-10-30 23:09:22 +00006import weakref
Jeremy Hyltonc5007aa2000-06-30 05:02:53 +00007
Guido van Rossumd8faa362007-04-27 19:54:29 +00008### Support code
9###############################################################################
Tim Peters0f81ab62003-04-08 16:39:48 +000010
Tim Petersead8b7a2004-10-30 23:09:22 +000011# Bug 1055820 has several tests of longstanding bugs involving weakrefs and
12# cyclic gc.
13
14# An instance of C1055820 has a self-loop, so becomes cyclic trash when
15# unreachable.
16class C1055820(object):
17 def __init__(self, i):
18 self.i = i
19 self.loop = self
20
21class GC_Detector(object):
22 # Create an instance I. Then gc hasn't happened again so long as
23 # I.gc_happened is false.
24
25 def __init__(self):
26 self.gc_happened = False
27
28 def it_happened(ignored):
29 self.gc_happened = True
30
31 # Create a piece of cyclic trash that triggers it_happened when
32 # gc collects it.
33 self.wr = weakref.ref(C1055820(666), it_happened)
34
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +000035class Uncollectable(object):
36 """Create a reference cycle with multiple __del__ methods.
37
38 An object in a reference cycle will never have zero references,
39 and so must be garbage collected. If one or more objects in the
40 cycle have __del__ methods, the gc refuses to guess an order,
41 and leaves the cycle uncollected."""
42 def __init__(self, partner=None):
43 if partner is None:
44 self.partner = Uncollectable(partner=self)
45 else:
46 self.partner = partner
47 def __del__(self):
48 pass
Tim Petersead8b7a2004-10-30 23:09:22 +000049
Guido van Rossumd8faa362007-04-27 19:54:29 +000050### Tests
51###############################################################################
Tim Petersead8b7a2004-10-30 23:09:22 +000052
Guido van Rossumd8faa362007-04-27 19:54:29 +000053class GCTests(unittest.TestCase):
54 def test_list(self):
55 l = []
56 l.append(l)
57 gc.collect()
58 del l
59 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +000060
Guido van Rossumd8faa362007-04-27 19:54:29 +000061 def test_dict(self):
62 d = {}
63 d[1] = d
64 gc.collect()
65 del d
66 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +000067
Guido van Rossumd8faa362007-04-27 19:54:29 +000068 def test_tuple(self):
69 # since tuples are immutable we close the loop with a list
70 l = []
71 t = (l,)
72 l.append(t)
73 gc.collect()
74 del t
75 del l
76 self.assertEqual(gc.collect(), 2)
Tim Petersead8b7a2004-10-30 23:09:22 +000077
Guido van Rossumd8faa362007-04-27 19:54:29 +000078 def test_class(self):
79 class A:
80 pass
81 A.a = A
82 gc.collect()
83 del A
84 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +000085
Guido van Rossumd8faa362007-04-27 19:54:29 +000086 def test_newstyleclass(self):
87 class A(object):
88 pass
89 gc.collect()
90 del A
91 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +000092
Guido van Rossumd8faa362007-04-27 19:54:29 +000093 def test_instance(self):
94 class A:
95 pass
96 a = A()
97 a.a = a
98 gc.collect()
99 del a
100 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000101
Guido van Rossumd8faa362007-04-27 19:54:29 +0000102 def test_newinstance(self):
103 class A(object):
104 pass
105 a = A()
106 a.a = a
107 gc.collect()
108 del a
109 self.assertNotEqual(gc.collect(), 0)
110 class B(list):
111 pass
112 class C(B, A):
113 pass
114 a = C()
115 a.a = a
116 gc.collect()
117 del a
118 self.assertNotEqual(gc.collect(), 0)
119 del B, C
120 self.assertNotEqual(gc.collect(), 0)
121 A.a = A()
122 del A
123 self.assertNotEqual(gc.collect(), 0)
124 self.assertEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000125
Guido van Rossumd8faa362007-04-27 19:54:29 +0000126 def test_method(self):
127 # Tricky: self.__init__ is a bound method, it references the instance.
128 class A:
129 def __init__(self):
130 self.init = self.__init__
131 a = A()
132 gc.collect()
133 del a
134 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000135
Guido van Rossumd8faa362007-04-27 19:54:29 +0000136 def test_finalizer(self):
137 # A() is uncollectable if it is part of a cycle, make sure it shows up
138 # in gc.garbage.
139 class A:
140 def __del__(self): pass
141 class B:
142 pass
143 a = A()
144 a.a = a
145 id_a = id(a)
146 b = B()
147 b.b = b
148 gc.collect()
149 del a
150 del b
151 self.assertNotEqual(gc.collect(), 0)
152 for obj in gc.garbage:
153 if id(obj) == id_a:
154 del obj.a
155 break
156 else:
157 self.fail("didn't find obj in garbage (finalizer)")
158 gc.garbage.remove(obj)
Tim Petersead8b7a2004-10-30 23:09:22 +0000159
Guido van Rossumd8faa362007-04-27 19:54:29 +0000160 def test_finalizer_newclass(self):
161 # A() is uncollectable if it is part of a cycle, make sure it shows up
162 # in gc.garbage.
163 class A(object):
164 def __del__(self): pass
165 class B(object):
166 pass
167 a = A()
168 a.a = a
169 id_a = id(a)
170 b = B()
171 b.b = b
172 gc.collect()
173 del a
174 del b
175 self.assertNotEqual(gc.collect(), 0)
176 for obj in gc.garbage:
177 if id(obj) == id_a:
178 del obj.a
179 break
180 else:
181 self.fail("didn't find obj in garbage (finalizer)")
182 gc.garbage.remove(obj)
Tim Petersead8b7a2004-10-30 23:09:22 +0000183
Guido van Rossumd8faa362007-04-27 19:54:29 +0000184 def test_function(self):
185 # Tricky: f -> d -> f, code should call d.clear() after the exec to
186 # break the cycle.
187 d = {}
188 exec("def f(): pass\n", d)
189 gc.collect()
190 del d
191 self.assertEqual(gc.collect(), 2)
Tim Petersead8b7a2004-10-30 23:09:22 +0000192
Brett Cannon7a540732011-02-22 03:04:06 +0000193 @refcount_test
Guido van Rossumd8faa362007-04-27 19:54:29 +0000194 def test_frame(self):
195 def f():
196 frame = sys._getframe()
197 gc.collect()
198 f()
199 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +0000200
Guido van Rossumd8faa362007-04-27 19:54:29 +0000201 def test_saveall(self):
202 # Verify that cyclic garbage like lists show up in gc.garbage if the
203 # SAVEALL option is enabled.
Tim Petersead8b7a2004-10-30 23:09:22 +0000204
Guido van Rossumd8faa362007-04-27 19:54:29 +0000205 # First make sure we don't save away other stuff that just happens to
206 # be waiting for collection.
207 gc.collect()
208 # if this fails, someone else created immortal trash
209 self.assertEqual(gc.garbage, [])
210
211 L = []
212 L.append(L)
213 id_L = id(L)
214
215 debug = gc.get_debug()
216 gc.set_debug(debug | gc.DEBUG_SAVEALL)
217 del L
218 gc.collect()
219 gc.set_debug(debug)
220
221 self.assertEqual(len(gc.garbage), 1)
222 obj = gc.garbage.pop()
223 self.assertEqual(id(obj), id_L)
224
225 def test_del(self):
226 # __del__ methods can trigger collection, make this to happen
227 thresholds = gc.get_threshold()
228 gc.enable()
229 gc.set_threshold(1)
230
231 class A:
232 def __del__(self):
233 dir(self)
234 a = A()
235 del a
236
237 gc.disable()
238 gc.set_threshold(*thresholds)
239
240 def test_del_newclass(self):
241 # __del__ methods can trigger collection, make this to happen
242 thresholds = gc.get_threshold()
243 gc.enable()
244 gc.set_threshold(1)
245
246 class A(object):
247 def __del__(self):
248 dir(self)
249 a = A()
250 del a
251
252 gc.disable()
253 gc.set_threshold(*thresholds)
254
Christian Heimesa156e092008-02-16 07:38:31 +0000255 # The following two tests are fragile:
256 # They precisely count the number of allocations,
257 # which is highly implementation-dependent.
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200258 # For example, disposed tuples are not freed, but reused.
259 # To minimize variations, though, we first store the get_count() results
260 # and check them at the end.
Brett Cannon7a540732011-02-22 03:04:06 +0000261 @refcount_test
Guido van Rossumd8faa362007-04-27 19:54:29 +0000262 def test_get_count(self):
263 gc.collect()
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200264 a, b, c = gc.get_count()
265 x = []
266 d, e, f = gc.get_count()
267 self.assertEqual((b, c), (0, 0))
268 self.assertEqual((e, f), (0, 0))
269 # This is less fragile than asserting that a equals 0.
270 self.assertLess(a, 5)
271 # Between the two calls to get_count(), at least one object was
272 # created (the list).
273 self.assertGreater(d, a)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000274
Brett Cannon7a540732011-02-22 03:04:06 +0000275 @refcount_test
Guido van Rossumd8faa362007-04-27 19:54:29 +0000276 def test_collect_generations(self):
277 gc.collect()
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200278 # This object will "trickle" into generation N + 1 after
279 # each call to collect(N)
280 x = []
Guido van Rossumd8faa362007-04-27 19:54:29 +0000281 gc.collect(0)
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200282 # x is now in gen 1
283 a, b, c = gc.get_count()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000284 gc.collect(1)
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200285 # x is now in gen 2
286 d, e, f = gc.get_count()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000287 gc.collect(2)
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200288 # x is now in gen 3
289 g, h, i = gc.get_count()
290 # We don't check a, d, g since their exact values depends on
291 # internal implementation details of the interpreter.
292 self.assertEqual((b, c), (1, 0))
293 self.assertEqual((e, f), (0, 1))
294 self.assertEqual((h, i), (0, 0))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000295
296 def test_trashcan(self):
297 class Ouch:
298 n = 0
299 def __del__(self):
300 Ouch.n = Ouch.n + 1
301 if Ouch.n % 17 == 0:
302 gc.collect()
303
304 # "trashcan" is a hack to prevent stack overflow when deallocating
305 # very deeply nested tuples etc. It works in part by abusing the
306 # type pointer and refcount fields, and that can yield horrible
307 # problems when gc tries to traverse the structures.
308 # If this test fails (as it does in 2.0, 2.1 and 2.2), it will
309 # most likely die via segfault.
310
311 # Note: In 2.3 the possibility for compiling without cyclic gc was
312 # removed, and that in turn allows the trashcan mechanism to work
313 # via much simpler means (e.g., it never abuses the type pointer or
314 # refcount fields anymore). Since it's much less likely to cause a
315 # problem now, the various constants in this expensive (we force a lot
316 # of full collections) test are cut back from the 2.2 version.
317 gc.enable()
318 N = 150
319 for count in range(2):
320 t = []
321 for i in range(N):
322 t = [t, Ouch()]
323 u = []
324 for i in range(N):
325 u = [u, Ouch()]
326 v = {}
327 for i in range(N):
328 v = {1: v, 2: Ouch()}
329 gc.disable()
330
331 def test_boom(self):
332 class Boom:
333 def __getattr__(self, someattribute):
334 del self.attr
335 raise AttributeError
336
337 a = Boom()
338 b = Boom()
339 a.attr = b
340 b.attr = a
341
342 gc.collect()
343 garbagelen = len(gc.garbage)
344 del a, b
345 # a<->b are in a trash cycle now. Collection will invoke
346 # Boom.__getattr__ (to see whether a and b have __del__ methods), and
347 # __getattr__ deletes the internal "attr" attributes as a side effect.
348 # That causes the trash cycle to get reclaimed via refcounts falling to
349 # 0, thus mutating the trash graph as a side effect of merely asking
350 # whether __del__ exists. This used to (before 2.3b1) crash Python.
351 # Now __getattr__ isn't called.
352 self.assertEqual(gc.collect(), 4)
353 self.assertEqual(len(gc.garbage), garbagelen)
354
355 def test_boom2(self):
356 class Boom2:
357 def __init__(self):
358 self.x = 0
359
360 def __getattr__(self, someattribute):
361 self.x += 1
362 if self.x > 1:
363 del self.attr
364 raise AttributeError
365
366 a = Boom2()
367 b = Boom2()
368 a.attr = b
369 b.attr = a
370
371 gc.collect()
372 garbagelen = len(gc.garbage)
373 del a, b
374 # Much like test_boom(), except that __getattr__ doesn't break the
375 # cycle until the second time gc checks for __del__. As of 2.3b1,
376 # there isn't a second time, so this simply cleans up the trash cycle.
377 # We expect a, b, a.__dict__ and b.__dict__ (4 objects) to get
378 # reclaimed this way.
379 self.assertEqual(gc.collect(), 4)
380 self.assertEqual(len(gc.garbage), garbagelen)
381
382 def test_boom_new(self):
383 # boom__new and boom2_new are exactly like boom and boom2, except use
384 # new-style classes.
385
386 class Boom_New(object):
387 def __getattr__(self, someattribute):
388 del self.attr
389 raise AttributeError
390
391 a = Boom_New()
392 b = Boom_New()
393 a.attr = b
394 b.attr = a
395
396 gc.collect()
397 garbagelen = len(gc.garbage)
398 del a, b
399 self.assertEqual(gc.collect(), 4)
400 self.assertEqual(len(gc.garbage), garbagelen)
401
402 def test_boom2_new(self):
403 class Boom2_New(object):
404 def __init__(self):
405 self.x = 0
406
407 def __getattr__(self, someattribute):
408 self.x += 1
409 if self.x > 1:
410 del self.attr
411 raise AttributeError
412
413 a = Boom2_New()
414 b = Boom2_New()
415 a.attr = b
416 b.attr = a
417
418 gc.collect()
419 garbagelen = len(gc.garbage)
420 del a, b
421 self.assertEqual(gc.collect(), 4)
422 self.assertEqual(len(gc.garbage), garbagelen)
423
424 def test_get_referents(self):
425 alist = [1, 3, 5]
426 got = gc.get_referents(alist)
427 got.sort()
428 self.assertEqual(got, alist)
429
430 atuple = tuple(alist)
431 got = gc.get_referents(atuple)
432 got.sort()
433 self.assertEqual(got, alist)
434
435 adict = {1: 3, 5: 7}
436 expected = [1, 3, 5, 7]
437 got = gc.get_referents(adict)
438 got.sort()
439 self.assertEqual(got, expected)
440
441 got = gc.get_referents([1, 2], {3: 4}, (0, 0, 0))
442 got.sort()
Guido van Rossum805365e2007-05-07 22:24:25 +0000443 self.assertEqual(got, [0, 0] + list(range(5)))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000444
445 self.assertEqual(gc.get_referents(1, 'a', 4j), [])
446
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000447 def test_is_tracked(self):
448 # Atomic built-in types are not tracked, user-defined objects and
449 # mutable containers are.
450 # NOTE: types with special optimizations (e.g. tuple) have tests
451 # in their own test files instead.
452 self.assertFalse(gc.is_tracked(None))
453 self.assertFalse(gc.is_tracked(1))
454 self.assertFalse(gc.is_tracked(1.0))
455 self.assertFalse(gc.is_tracked(1.0 + 5.0j))
456 self.assertFalse(gc.is_tracked(True))
457 self.assertFalse(gc.is_tracked(False))
458 self.assertFalse(gc.is_tracked(b"a"))
459 self.assertFalse(gc.is_tracked("a"))
460 self.assertFalse(gc.is_tracked(bytearray(b"a")))
461 self.assertFalse(gc.is_tracked(type))
462 self.assertFalse(gc.is_tracked(int))
463 self.assertFalse(gc.is_tracked(object))
464 self.assertFalse(gc.is_tracked(object()))
465
466 class UserClass:
467 pass
468 self.assertTrue(gc.is_tracked(gc))
469 self.assertTrue(gc.is_tracked(UserClass))
470 self.assertTrue(gc.is_tracked(UserClass()))
471 self.assertTrue(gc.is_tracked([]))
472 self.assertTrue(gc.is_tracked(set()))
473
Guido van Rossumd8faa362007-04-27 19:54:29 +0000474 def test_bug1055820b(self):
475 # Corresponds to temp2b.py in the bug report.
476
477 ouch = []
478 def callback(ignored):
479 ouch[:] = [wr() for wr in WRs]
480
481 Cs = [C1055820(i) for i in range(2)]
482 WRs = [weakref.ref(c, callback) for c in Cs]
483 c = None
484
485 gc.collect()
486 self.assertEqual(len(ouch), 0)
487 # Make the two instances trash, and collect again. The bug was that
488 # the callback materialized a strong reference to an instance, but gc
489 # cleared the instance's dict anyway.
490 Cs = None
491 gc.collect()
492 self.assertEqual(len(ouch), 2) # else the callbacks didn't run
493 for x in ouch:
494 # If the callback resurrected one of these guys, the instance
495 # would be damaged, with an empty __dict__.
496 self.assertEqual(x, None)
497
Antoine Pitrou696e0352010-08-08 22:18:46 +0000498 def test_garbage_at_shutdown(self):
499 import subprocess
500 code = """if 1:
501 import gc
502 class X:
503 def __init__(self, name):
504 self.name = name
505 def __repr__(self):
506 return "<X %%r>" %% self.name
507 def __del__(self):
508 pass
509
510 x = X('first')
511 x.x = x
512 x.y = X('second')
513 del x
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000514 gc.set_debug(%s)
Antoine Pitrou696e0352010-08-08 22:18:46 +0000515 """
516 def run_command(code):
Georg Brandl08be72d2010-10-24 15:11:22 +0000517 p = subprocess.Popen([sys.executable, "-Wd", "-c", code],
Antoine Pitrou696e0352010-08-08 22:18:46 +0000518 stdout=subprocess.PIPE,
519 stderr=subprocess.PIPE)
520 stdout, stderr = p.communicate()
Brian Curtin8291af22010-11-01 16:40:17 +0000521 p.stdout.close()
522 p.stderr.close()
Antoine Pitrou696e0352010-08-08 22:18:46 +0000523 self.assertEqual(p.returncode, 0)
524 self.assertEqual(stdout.strip(), b"")
525 return strip_python_stderr(stderr)
526
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000527 stderr = run_command(code % "0")
Georg Brandl08be72d2010-10-24 15:11:22 +0000528 self.assertIn(b"ResourceWarning: gc: 2 uncollectable objects at "
529 b"shutdown; use", stderr)
Antoine Pitrouaee47562010-09-16 15:04:49 +0000530 self.assertNotIn(b"<X 'first'>", stderr)
Antoine Pitrou696e0352010-08-08 22:18:46 +0000531 # With DEBUG_UNCOLLECTABLE, the garbage list gets printed
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000532 stderr = run_command(code % "gc.DEBUG_UNCOLLECTABLE")
Georg Brandl08be72d2010-10-24 15:11:22 +0000533 self.assertIn(b"ResourceWarning: gc: 2 uncollectable objects at "
534 b"shutdown", stderr)
Antoine Pitrouaee47562010-09-16 15:04:49 +0000535 self.assertTrue(
536 (b"[<X 'first'>, <X 'second'>]" in stderr) or
537 (b"[<X 'second'>, <X 'first'>]" in stderr), stderr)
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000538 # With DEBUG_SAVEALL, no additional message should get printed
539 # (because gc.garbage also contains normally reclaimable cyclic
540 # references, and its elements get printed at runtime anyway).
541 stderr = run_command(code % "gc.DEBUG_SAVEALL")
542 self.assertNotIn(b"uncollectable objects at shutdown", stderr)
543
Antoine Pitrou696e0352010-08-08 22:18:46 +0000544
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000545class GCCallbackTests(unittest.TestCase):
546 def setUp(self):
547 # Save gc state and disable it.
548 self.enabled = gc.isenabled()
549 gc.disable()
550 self.debug = gc.get_debug()
551 gc.set_debug(0)
552 gc.callbacks.append(self.cb1)
553 gc.callbacks.append(self.cb2)
554
555 def tearDown(self):
556 # Restore gc state
557 del self.visit
558 gc.callbacks.remove(self.cb1)
559 gc.callbacks.remove(self.cb2)
560 gc.set_debug(self.debug)
561 if self.enabled:
562 gc.enable()
563 # destroy any uncollectables
564 gc.collect()
565 for obj in gc.garbage:
566 if isinstance(obj, Uncollectable):
567 obj.partner = None
568 del gc.garbage[:]
569 gc.collect()
570
571 othergarbage = []
572 def preclean(self):
573 # Remove all fluff from the system. Invoke this function
574 # manually rather than through self.setUp() for maximum
575 # safety.
576 self.visit = []
577 gc.collect()
578 garbage, gc.garbage[:] = gc.garbage[:], []
579 self.othergarbage.append(garbage)
580 self.visit = []
581
582 def cb1(self, phase, info):
583 self.visit.append((1, phase, dict(info)))
584
585 def cb2(self, phase, info):
586 self.visit.append((2, phase, dict(info)))
587 if phase == "stop" and hasattr(self, "cleanup"):
588 # Clean Uncollectable from garbage
589 uc = [e for e in gc.garbage if isinstance(e, Uncollectable)]
590 gc.garbage[:] = [e for e in gc.garbage
591 if not isinstance(e, Uncollectable)]
592 for e in uc:
593 e.partner = None
594
595 def testCollect(self):
596 self.preclean()
597 gc.collect()
598 # Algorithmically verify the contents of self.visit
599 # because it is long and tortuous.
600
601 # Count the number of visits to each callback
602 n = [v[0] for v in self.visit]
603 n1 = [i for i in n if i == 1]
604 n2 = [i for i in n if i == 2]
605 self.assertEqual(n1, [1]*2)
606 self.assertEqual(n2, [2]*2)
607
608 # Count that we got the right number of start and stop callbacks.
609 n = [v[1] for v in self.visit]
610 n1 = [i for i in n if i == "start"]
611 n2 = [i for i in n if i == "stop"]
612 self.assertEqual(n1, ["start"]*2)
613 self.assertEqual(n2, ["stop"]*2)
614
615 # Check that we got the right info dict for all callbacks
616 for v in self.visit:
617 info = v[2]
618 self.assertTrue("generation" in info)
619 self.assertTrue("collected" in info)
620 self.assertTrue("uncollectable" in info)
621
622 def testCollectGen(self):
623 self.preclean()
624 gc.collect(2)
625 for v in self.visit:
626 info = v[2]
627 self.assertEqual(info["generation"], 2)
628
629 def testCollectGarbage(self):
630 self.preclean()
631 # Each of these cause four objects to be garbage: Two
632 # Uncolectables and their instance dicts.
633 Uncollectable()
634 Uncollectable()
635 C1055820(666)
636 gc.collect()
637 for v in self.visit:
638 if v[1] != "stop":
639 continue
640 info = v[2]
641 self.assertEqual(info["collected"], 2)
642 self.assertEqual(info["uncollectable"], 8)
643
644 # We should now have the Uncollectables in gc.garbage
645 self.assertEqual(len(gc.garbage), 4)
646 for e in gc.garbage:
647 self.assertIsInstance(e, Uncollectable)
648
649 # Now, let our callback handle the Uncollectable instances
650 self.cleanup=True
651 self.visit = []
652 gc.garbage[:] = []
653 gc.collect()
654 for v in self.visit:
655 if v[1] != "stop":
656 continue
657 info = v[2]
658 self.assertEqual(info["collected"], 0)
659 self.assertEqual(info["uncollectable"], 4)
660
661 # Uncollectables should be gone
662 self.assertEqual(len(gc.garbage), 0)
663
664
Guido van Rossumd8faa362007-04-27 19:54:29 +0000665class GCTogglingTests(unittest.TestCase):
666 def setUp(self):
667 gc.enable()
668
669 def tearDown(self):
670 gc.disable()
671
672 def test_bug1055820c(self):
673 # Corresponds to temp2c.py in the bug report. This is pretty
674 # elaborate.
675
676 c0 = C1055820(0)
677 # Move c0 into generation 2.
678 gc.collect()
679
680 c1 = C1055820(1)
681 c1.keep_c0_alive = c0
682 del c0.loop # now only c1 keeps c0 alive
683
684 c2 = C1055820(2)
685 c2wr = weakref.ref(c2) # no callback!
686
687 ouch = []
688 def callback(ignored):
Tim Petersead8b7a2004-10-30 23:09:22 +0000689 ouch[:] = [c2wr()]
690
Guido van Rossumd8faa362007-04-27 19:54:29 +0000691 # The callback gets associated with a wr on an object in generation 2.
692 c0wr = weakref.ref(c0, callback)
Tim Petersead8b7a2004-10-30 23:09:22 +0000693
Guido van Rossumd8faa362007-04-27 19:54:29 +0000694 c0 = c1 = c2 = None
Tim Petersead8b7a2004-10-30 23:09:22 +0000695
Guido van Rossumd8faa362007-04-27 19:54:29 +0000696 # What we've set up: c0, c1, and c2 are all trash now. c0 is in
697 # generation 2. The only thing keeping it alive is that c1 points to
698 # it. c1 and c2 are in generation 0, and are in self-loops. There's a
699 # global weakref to c2 (c2wr), but that weakref has no callback.
700 # There's also a global weakref to c0 (c0wr), and that does have a
701 # callback, and that callback references c2 via c2wr().
702 #
703 # c0 has a wr with callback, which references c2wr
704 # ^
705 # |
706 # | Generation 2 above dots
707 #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .
708 # | Generation 0 below dots
709 # |
710 # |
711 # ^->c1 ^->c2 has a wr but no callback
712 # | | | |
713 # <--v <--v
714 #
715 # So this is the nightmare: when generation 0 gets collected, we see
716 # that c2 has a callback-free weakref, and c1 doesn't even have a
717 # weakref. Collecting generation 0 doesn't see c0 at all, and c0 is
718 # the only object that has a weakref with a callback. gc clears c1
719 # and c2. Clearing c1 has the side effect of dropping the refcount on
720 # c0 to 0, so c0 goes away (despite that it's in an older generation)
721 # and c0's wr callback triggers. That in turn materializes a reference
722 # to c2 via c2wr(), but c2 gets cleared anyway by gc.
Tim Petersead8b7a2004-10-30 23:09:22 +0000723
Guido van Rossumd8faa362007-04-27 19:54:29 +0000724 # We want to let gc happen "naturally", to preserve the distinction
725 # between generations.
726 junk = []
727 i = 0
728 detector = GC_Detector()
729 while not detector.gc_happened:
730 i += 1
731 if i > 10000:
732 self.fail("gc didn't happen after 10000 iterations")
733 self.assertEqual(len(ouch), 0)
734 junk.append([]) # this will eventually trigger gc
Tim Petersead8b7a2004-10-30 23:09:22 +0000735
Guido van Rossumd8faa362007-04-27 19:54:29 +0000736 self.assertEqual(len(ouch), 1) # else the callback wasn't invoked
737 for x in ouch:
738 # If the callback resurrected c2, the instance would be damaged,
739 # with an empty __dict__.
740 self.assertEqual(x, None)
Tim Petersead8b7a2004-10-30 23:09:22 +0000741
Guido van Rossumd8faa362007-04-27 19:54:29 +0000742 def test_bug1055820d(self):
743 # Corresponds to temp2d.py in the bug report. This is very much like
744 # test_bug1055820c, but uses a __del__ method instead of a weakref
745 # callback to sneak in a resurrection of cyclic trash.
Tim Petersead8b7a2004-10-30 23:09:22 +0000746
Guido van Rossumd8faa362007-04-27 19:54:29 +0000747 ouch = []
748 class D(C1055820):
749 def __del__(self):
750 ouch[:] = [c2wr()]
Tim Petersead8b7a2004-10-30 23:09:22 +0000751
Guido van Rossumd8faa362007-04-27 19:54:29 +0000752 d0 = D(0)
753 # Move all the above into generation 2.
754 gc.collect()
Tim Petersead8b7a2004-10-30 23:09:22 +0000755
Guido van Rossumd8faa362007-04-27 19:54:29 +0000756 c1 = C1055820(1)
757 c1.keep_d0_alive = d0
758 del d0.loop # now only c1 keeps d0 alive
Tim Petersead8b7a2004-10-30 23:09:22 +0000759
Guido van Rossumd8faa362007-04-27 19:54:29 +0000760 c2 = C1055820(2)
761 c2wr = weakref.ref(c2) # no callback!
Tim Petersead8b7a2004-10-30 23:09:22 +0000762
Guido van Rossumd8faa362007-04-27 19:54:29 +0000763 d0 = c1 = c2 = None
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000764
Guido van Rossumd8faa362007-04-27 19:54:29 +0000765 # What we've set up: d0, c1, and c2 are all trash now. d0 is in
766 # generation 2. The only thing keeping it alive is that c1 points to
767 # it. c1 and c2 are in generation 0, and are in self-loops. There's
768 # a global weakref to c2 (c2wr), but that weakref has no callback.
769 # There are no other weakrefs.
770 #
771 # d0 has a __del__ method that references c2wr
772 # ^
773 # |
774 # | Generation 2 above dots
775 #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .
776 # | Generation 0 below dots
777 # |
778 # |
779 # ^->c1 ^->c2 has a wr but no callback
780 # | | | |
781 # <--v <--v
782 #
783 # So this is the nightmare: when generation 0 gets collected, we see
784 # that c2 has a callback-free weakref, and c1 doesn't even have a
785 # weakref. Collecting generation 0 doesn't see d0 at all. gc clears
786 # c1 and c2. Clearing c1 has the side effect of dropping the refcount
787 # on d0 to 0, so d0 goes away (despite that it's in an older
788 # generation) and d0's __del__ triggers. That in turn materializes
789 # a reference to c2 via c2wr(), but c2 gets cleared anyway by gc.
790
791 # We want to let gc happen "naturally", to preserve the distinction
792 # between generations.
793 detector = GC_Detector()
794 junk = []
795 i = 0
796 while not detector.gc_happened:
797 i += 1
798 if i > 10000:
799 self.fail("gc didn't happen after 10000 iterations")
800 self.assertEqual(len(ouch), 0)
801 junk.append([]) # this will eventually trigger gc
802
803 self.assertEqual(len(ouch), 1) # else __del__ wasn't invoked
804 for x in ouch:
805 # If __del__ resurrected c2, the instance would be damaged, with an
806 # empty __dict__.
807 self.assertEqual(x, None)
808
809def test_main():
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000810 enabled = gc.isenabled()
811 gc.disable()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000812 assert not gc.isenabled()
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000813 debug = gc.get_debug()
814 gc.set_debug(debug & ~gc.DEBUG_LEAK) # this test is supposed to leak
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000815
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000816 try:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000817 gc.collect() # Delete 2nd generation garbage
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000818 run_unittest(GCTests, GCTogglingTests, GCCallbackTests)
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000819 finally:
820 gc.set_debug(debug)
821 # test gc.enable() even if GC is disabled by default
822 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000823 print("restoring automatic collection")
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000824 # make sure to always test gc.enable()
825 gc.enable()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000826 assert gc.isenabled()
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000827 if not enabled:
828 gc.disable()
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000829
Guido van Rossumd8faa362007-04-27 19:54:29 +0000830if __name__ == "__main__":
831 test_main()