blob: c59b72eacf87fa81cdc328d2672b0311231e9293 [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
Antoine Pitrou2b0218a2012-09-06 00:59:49 +02005import time
Jeremy Hyltonc5007aa2000-06-30 05:02:53 +00006import gc
Tim Petersead8b7a2004-10-30 23:09:22 +00007import weakref
Jeremy Hyltonc5007aa2000-06-30 05:02:53 +00008
Antoine Pitrou2b0218a2012-09-06 00:59:49 +02009try:
10 import threading
11except ImportError:
12 threading = None
13
Guido van Rossumd8faa362007-04-27 19:54:29 +000014### Support code
15###############################################################################
Tim Peters0f81ab62003-04-08 16:39:48 +000016
Tim Petersead8b7a2004-10-30 23:09:22 +000017# Bug 1055820 has several tests of longstanding bugs involving weakrefs and
18# cyclic gc.
19
20# An instance of C1055820 has a self-loop, so becomes cyclic trash when
21# unreachable.
22class C1055820(object):
23 def __init__(self, i):
24 self.i = i
25 self.loop = self
26
27class GC_Detector(object):
28 # Create an instance I. Then gc hasn't happened again so long as
29 # I.gc_happened is false.
30
31 def __init__(self):
32 self.gc_happened = False
33
34 def it_happened(ignored):
35 self.gc_happened = True
36
37 # Create a piece of cyclic trash that triggers it_happened when
38 # gc collects it.
39 self.wr = weakref.ref(C1055820(666), it_happened)
40
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +000041class Uncollectable(object):
42 """Create a reference cycle with multiple __del__ methods.
43
44 An object in a reference cycle will never have zero references,
45 and so must be garbage collected. If one or more objects in the
46 cycle have __del__ methods, the gc refuses to guess an order,
47 and leaves the cycle uncollected."""
48 def __init__(self, partner=None):
49 if partner is None:
50 self.partner = Uncollectable(partner=self)
51 else:
52 self.partner = partner
53 def __del__(self):
54 pass
Tim Petersead8b7a2004-10-30 23:09:22 +000055
Guido van Rossumd8faa362007-04-27 19:54:29 +000056### Tests
57###############################################################################
Tim Petersead8b7a2004-10-30 23:09:22 +000058
Guido van Rossumd8faa362007-04-27 19:54:29 +000059class GCTests(unittest.TestCase):
60 def test_list(self):
61 l = []
62 l.append(l)
63 gc.collect()
64 del l
65 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +000066
Guido van Rossumd8faa362007-04-27 19:54:29 +000067 def test_dict(self):
68 d = {}
69 d[1] = d
70 gc.collect()
71 del d
72 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +000073
Guido van Rossumd8faa362007-04-27 19:54:29 +000074 def test_tuple(self):
75 # since tuples are immutable we close the loop with a list
76 l = []
77 t = (l,)
78 l.append(t)
79 gc.collect()
80 del t
81 del l
82 self.assertEqual(gc.collect(), 2)
Tim Petersead8b7a2004-10-30 23:09:22 +000083
Guido van Rossumd8faa362007-04-27 19:54:29 +000084 def test_class(self):
85 class A:
86 pass
87 A.a = A
88 gc.collect()
89 del A
90 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +000091
Guido van Rossumd8faa362007-04-27 19:54:29 +000092 def test_newstyleclass(self):
93 class A(object):
94 pass
95 gc.collect()
96 del A
97 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +000098
Guido van Rossumd8faa362007-04-27 19:54:29 +000099 def test_instance(self):
100 class A:
101 pass
102 a = A()
103 a.a = a
104 gc.collect()
105 del a
106 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000107
Guido van Rossumd8faa362007-04-27 19:54:29 +0000108 def test_newinstance(self):
109 class A(object):
110 pass
111 a = A()
112 a.a = a
113 gc.collect()
114 del a
115 self.assertNotEqual(gc.collect(), 0)
116 class B(list):
117 pass
118 class C(B, A):
119 pass
120 a = C()
121 a.a = a
122 gc.collect()
123 del a
124 self.assertNotEqual(gc.collect(), 0)
125 del B, C
126 self.assertNotEqual(gc.collect(), 0)
127 A.a = A()
128 del A
129 self.assertNotEqual(gc.collect(), 0)
130 self.assertEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000131
Guido van Rossumd8faa362007-04-27 19:54:29 +0000132 def test_method(self):
133 # Tricky: self.__init__ is a bound method, it references the instance.
134 class A:
135 def __init__(self):
136 self.init = self.__init__
137 a = A()
138 gc.collect()
139 del a
140 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000141
Guido van Rossumd8faa362007-04-27 19:54:29 +0000142 def test_finalizer(self):
143 # A() is uncollectable if it is part of a cycle, make sure it shows up
144 # in gc.garbage.
145 class A:
146 def __del__(self): pass
147 class B:
148 pass
149 a = A()
150 a.a = a
151 id_a = id(a)
152 b = B()
153 b.b = b
154 gc.collect()
155 del a
156 del b
157 self.assertNotEqual(gc.collect(), 0)
158 for obj in gc.garbage:
159 if id(obj) == id_a:
160 del obj.a
161 break
162 else:
163 self.fail("didn't find obj in garbage (finalizer)")
164 gc.garbage.remove(obj)
Tim Petersead8b7a2004-10-30 23:09:22 +0000165
Guido van Rossumd8faa362007-04-27 19:54:29 +0000166 def test_finalizer_newclass(self):
167 # A() is uncollectable if it is part of a cycle, make sure it shows up
168 # in gc.garbage.
169 class A(object):
170 def __del__(self): pass
171 class B(object):
172 pass
173 a = A()
174 a.a = a
175 id_a = id(a)
176 b = B()
177 b.b = b
178 gc.collect()
179 del a
180 del b
181 self.assertNotEqual(gc.collect(), 0)
182 for obj in gc.garbage:
183 if id(obj) == id_a:
184 del obj.a
185 break
186 else:
187 self.fail("didn't find obj in garbage (finalizer)")
188 gc.garbage.remove(obj)
Tim Petersead8b7a2004-10-30 23:09:22 +0000189
Guido van Rossumd8faa362007-04-27 19:54:29 +0000190 def test_function(self):
191 # Tricky: f -> d -> f, code should call d.clear() after the exec to
192 # break the cycle.
193 d = {}
194 exec("def f(): pass\n", d)
195 gc.collect()
196 del d
197 self.assertEqual(gc.collect(), 2)
Tim Petersead8b7a2004-10-30 23:09:22 +0000198
Brett Cannon7a540732011-02-22 03:04:06 +0000199 @refcount_test
Guido van Rossumd8faa362007-04-27 19:54:29 +0000200 def test_frame(self):
201 def f():
202 frame = sys._getframe()
203 gc.collect()
204 f()
205 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +0000206
Guido van Rossumd8faa362007-04-27 19:54:29 +0000207 def test_saveall(self):
208 # Verify that cyclic garbage like lists show up in gc.garbage if the
209 # SAVEALL option is enabled.
Tim Petersead8b7a2004-10-30 23:09:22 +0000210
Guido van Rossumd8faa362007-04-27 19:54:29 +0000211 # First make sure we don't save away other stuff that just happens to
212 # be waiting for collection.
213 gc.collect()
214 # if this fails, someone else created immortal trash
215 self.assertEqual(gc.garbage, [])
216
217 L = []
218 L.append(L)
219 id_L = id(L)
220
221 debug = gc.get_debug()
222 gc.set_debug(debug | gc.DEBUG_SAVEALL)
223 del L
224 gc.collect()
225 gc.set_debug(debug)
226
227 self.assertEqual(len(gc.garbage), 1)
228 obj = gc.garbage.pop()
229 self.assertEqual(id(obj), id_L)
230
231 def test_del(self):
232 # __del__ methods can trigger collection, make this to happen
233 thresholds = gc.get_threshold()
234 gc.enable()
235 gc.set_threshold(1)
236
237 class A:
238 def __del__(self):
239 dir(self)
240 a = A()
241 del a
242
243 gc.disable()
244 gc.set_threshold(*thresholds)
245
246 def test_del_newclass(self):
247 # __del__ methods can trigger collection, make this to happen
248 thresholds = gc.get_threshold()
249 gc.enable()
250 gc.set_threshold(1)
251
252 class A(object):
253 def __del__(self):
254 dir(self)
255 a = A()
256 del a
257
258 gc.disable()
259 gc.set_threshold(*thresholds)
260
Christian Heimesa156e092008-02-16 07:38:31 +0000261 # The following two tests are fragile:
262 # They precisely count the number of allocations,
263 # which is highly implementation-dependent.
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200264 # For example, disposed tuples are not freed, but reused.
265 # To minimize variations, though, we first store the get_count() results
266 # and check them at the end.
Brett Cannon7a540732011-02-22 03:04:06 +0000267 @refcount_test
Guido van Rossumd8faa362007-04-27 19:54:29 +0000268 def test_get_count(self):
269 gc.collect()
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200270 a, b, c = gc.get_count()
271 x = []
272 d, e, f = gc.get_count()
273 self.assertEqual((b, c), (0, 0))
274 self.assertEqual((e, f), (0, 0))
275 # This is less fragile than asserting that a equals 0.
276 self.assertLess(a, 5)
277 # Between the two calls to get_count(), at least one object was
278 # created (the list).
279 self.assertGreater(d, a)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000280
Brett Cannon7a540732011-02-22 03:04:06 +0000281 @refcount_test
Guido van Rossumd8faa362007-04-27 19:54:29 +0000282 def test_collect_generations(self):
283 gc.collect()
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200284 # This object will "trickle" into generation N + 1 after
285 # each call to collect(N)
286 x = []
Guido van Rossumd8faa362007-04-27 19:54:29 +0000287 gc.collect(0)
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200288 # x is now in gen 1
289 a, b, c = gc.get_count()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000290 gc.collect(1)
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200291 # x is now in gen 2
292 d, e, f = gc.get_count()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000293 gc.collect(2)
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200294 # x is now in gen 3
295 g, h, i = gc.get_count()
296 # We don't check a, d, g since their exact values depends on
297 # internal implementation details of the interpreter.
298 self.assertEqual((b, c), (1, 0))
299 self.assertEqual((e, f), (0, 1))
300 self.assertEqual((h, i), (0, 0))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000301
302 def test_trashcan(self):
303 class Ouch:
304 n = 0
305 def __del__(self):
306 Ouch.n = Ouch.n + 1
307 if Ouch.n % 17 == 0:
308 gc.collect()
309
310 # "trashcan" is a hack to prevent stack overflow when deallocating
311 # very deeply nested tuples etc. It works in part by abusing the
312 # type pointer and refcount fields, and that can yield horrible
313 # problems when gc tries to traverse the structures.
314 # If this test fails (as it does in 2.0, 2.1 and 2.2), it will
315 # most likely die via segfault.
316
317 # Note: In 2.3 the possibility for compiling without cyclic gc was
318 # removed, and that in turn allows the trashcan mechanism to work
319 # via much simpler means (e.g., it never abuses the type pointer or
320 # refcount fields anymore). Since it's much less likely to cause a
321 # problem now, the various constants in this expensive (we force a lot
322 # of full collections) test are cut back from the 2.2 version.
323 gc.enable()
324 N = 150
325 for count in range(2):
326 t = []
327 for i in range(N):
328 t = [t, Ouch()]
329 u = []
330 for i in range(N):
331 u = [u, Ouch()]
332 v = {}
333 for i in range(N):
334 v = {1: v, 2: Ouch()}
335 gc.disable()
336
Antoine Pitrou2b0218a2012-09-06 00:59:49 +0200337 @unittest.skipUnless(threading, "test meaningless on builds without threads")
338 def test_trashcan_threads(self):
339 # Issue #13992: trashcan mechanism should be thread-safe
340 NESTING = 60
341 N_THREADS = 2
342
343 def sleeper_gen():
344 """A generator that releases the GIL when closed or dealloc'ed."""
345 try:
346 yield
347 finally:
348 time.sleep(0.000001)
349
350 class C(list):
351 # Appending to a list is atomic, which avoids the use of a lock.
352 inits = []
353 dels = []
354 def __init__(self, alist):
355 self[:] = alist
356 C.inits.append(None)
357 def __del__(self):
358 # This __del__ is called by subtype_dealloc().
359 C.dels.append(None)
360 # `g` will release the GIL when garbage-collected. This
361 # helps assert subtype_dealloc's behaviour when threads
362 # switch in the middle of it.
363 g = sleeper_gen()
364 next(g)
365 # Now that __del__ is finished, subtype_dealloc will proceed
366 # to call list_dealloc, which also uses the trashcan mechanism.
367
368 def make_nested():
369 """Create a sufficiently nested container object so that the
370 trashcan mechanism is invoked when deallocating it."""
371 x = C([])
372 for i in range(NESTING):
373 x = [C([x])]
374 del x
375
376 def run_thread():
377 """Exercise make_nested() in a loop."""
378 while not exit:
379 make_nested()
380
381 old_switchinterval = sys.getswitchinterval()
382 sys.setswitchinterval(1e-5)
383 try:
384 exit = False
385 threads = []
386 for i in range(N_THREADS):
387 t = threading.Thread(target=run_thread)
388 threads.append(t)
389 for t in threads:
390 t.start()
391 time.sleep(1.0)
392 exit = True
393 for t in threads:
394 t.join()
395 finally:
396 sys.setswitchinterval(old_switchinterval)
397 gc.collect()
398 self.assertEqual(len(C.inits), len(C.dels))
399
Guido van Rossumd8faa362007-04-27 19:54:29 +0000400 def test_boom(self):
401 class Boom:
402 def __getattr__(self, someattribute):
403 del self.attr
404 raise AttributeError
405
406 a = Boom()
407 b = Boom()
408 a.attr = b
409 b.attr = a
410
411 gc.collect()
412 garbagelen = len(gc.garbage)
413 del a, b
414 # a<->b are in a trash cycle now. Collection will invoke
415 # Boom.__getattr__ (to see whether a and b have __del__ methods), and
416 # __getattr__ deletes the internal "attr" attributes as a side effect.
417 # That causes the trash cycle to get reclaimed via refcounts falling to
418 # 0, thus mutating the trash graph as a side effect of merely asking
419 # whether __del__ exists. This used to (before 2.3b1) crash Python.
420 # Now __getattr__ isn't called.
421 self.assertEqual(gc.collect(), 4)
422 self.assertEqual(len(gc.garbage), garbagelen)
423
424 def test_boom2(self):
425 class Boom2:
426 def __init__(self):
427 self.x = 0
428
429 def __getattr__(self, someattribute):
430 self.x += 1
431 if self.x > 1:
432 del self.attr
433 raise AttributeError
434
435 a = Boom2()
436 b = Boom2()
437 a.attr = b
438 b.attr = a
439
440 gc.collect()
441 garbagelen = len(gc.garbage)
442 del a, b
443 # Much like test_boom(), except that __getattr__ doesn't break the
444 # cycle until the second time gc checks for __del__. As of 2.3b1,
445 # there isn't a second time, so this simply cleans up the trash cycle.
446 # We expect a, b, a.__dict__ and b.__dict__ (4 objects) to get
447 # reclaimed this way.
448 self.assertEqual(gc.collect(), 4)
449 self.assertEqual(len(gc.garbage), garbagelen)
450
451 def test_boom_new(self):
452 # boom__new and boom2_new are exactly like boom and boom2, except use
453 # new-style classes.
454
455 class Boom_New(object):
456 def __getattr__(self, someattribute):
457 del self.attr
458 raise AttributeError
459
460 a = Boom_New()
461 b = Boom_New()
462 a.attr = b
463 b.attr = a
464
465 gc.collect()
466 garbagelen = len(gc.garbage)
467 del a, b
468 self.assertEqual(gc.collect(), 4)
469 self.assertEqual(len(gc.garbage), garbagelen)
470
471 def test_boom2_new(self):
472 class Boom2_New(object):
473 def __init__(self):
474 self.x = 0
475
476 def __getattr__(self, someattribute):
477 self.x += 1
478 if self.x > 1:
479 del self.attr
480 raise AttributeError
481
482 a = Boom2_New()
483 b = Boom2_New()
484 a.attr = b
485 b.attr = a
486
487 gc.collect()
488 garbagelen = len(gc.garbage)
489 del a, b
490 self.assertEqual(gc.collect(), 4)
491 self.assertEqual(len(gc.garbage), garbagelen)
492
493 def test_get_referents(self):
494 alist = [1, 3, 5]
495 got = gc.get_referents(alist)
496 got.sort()
497 self.assertEqual(got, alist)
498
499 atuple = tuple(alist)
500 got = gc.get_referents(atuple)
501 got.sort()
502 self.assertEqual(got, alist)
503
504 adict = {1: 3, 5: 7}
505 expected = [1, 3, 5, 7]
506 got = gc.get_referents(adict)
507 got.sort()
508 self.assertEqual(got, expected)
509
510 got = gc.get_referents([1, 2], {3: 4}, (0, 0, 0))
511 got.sort()
Guido van Rossum805365e2007-05-07 22:24:25 +0000512 self.assertEqual(got, [0, 0] + list(range(5)))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000513
514 self.assertEqual(gc.get_referents(1, 'a', 4j), [])
515
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000516 def test_is_tracked(self):
517 # Atomic built-in types are not tracked, user-defined objects and
518 # mutable containers are.
519 # NOTE: types with special optimizations (e.g. tuple) have tests
520 # in their own test files instead.
521 self.assertFalse(gc.is_tracked(None))
522 self.assertFalse(gc.is_tracked(1))
523 self.assertFalse(gc.is_tracked(1.0))
524 self.assertFalse(gc.is_tracked(1.0 + 5.0j))
525 self.assertFalse(gc.is_tracked(True))
526 self.assertFalse(gc.is_tracked(False))
527 self.assertFalse(gc.is_tracked(b"a"))
528 self.assertFalse(gc.is_tracked("a"))
529 self.assertFalse(gc.is_tracked(bytearray(b"a")))
530 self.assertFalse(gc.is_tracked(type))
531 self.assertFalse(gc.is_tracked(int))
532 self.assertFalse(gc.is_tracked(object))
533 self.assertFalse(gc.is_tracked(object()))
534
535 class UserClass:
536 pass
537 self.assertTrue(gc.is_tracked(gc))
538 self.assertTrue(gc.is_tracked(UserClass))
539 self.assertTrue(gc.is_tracked(UserClass()))
540 self.assertTrue(gc.is_tracked([]))
541 self.assertTrue(gc.is_tracked(set()))
542
Guido van Rossumd8faa362007-04-27 19:54:29 +0000543 def test_bug1055820b(self):
544 # Corresponds to temp2b.py in the bug report.
545
546 ouch = []
547 def callback(ignored):
548 ouch[:] = [wr() for wr in WRs]
549
550 Cs = [C1055820(i) for i in range(2)]
551 WRs = [weakref.ref(c, callback) for c in Cs]
552 c = None
553
554 gc.collect()
555 self.assertEqual(len(ouch), 0)
556 # Make the two instances trash, and collect again. The bug was that
557 # the callback materialized a strong reference to an instance, but gc
558 # cleared the instance's dict anyway.
559 Cs = None
560 gc.collect()
561 self.assertEqual(len(ouch), 2) # else the callbacks didn't run
562 for x in ouch:
563 # If the callback resurrected one of these guys, the instance
564 # would be damaged, with an empty __dict__.
565 self.assertEqual(x, None)
566
Antoine Pitrou696e0352010-08-08 22:18:46 +0000567 def test_garbage_at_shutdown(self):
568 import subprocess
569 code = """if 1:
570 import gc
571 class X:
572 def __init__(self, name):
573 self.name = name
574 def __repr__(self):
575 return "<X %%r>" %% self.name
576 def __del__(self):
577 pass
578
579 x = X('first')
580 x.x = x
581 x.y = X('second')
582 del x
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000583 gc.set_debug(%s)
Antoine Pitrou696e0352010-08-08 22:18:46 +0000584 """
585 def run_command(code):
Georg Brandl08be72d2010-10-24 15:11:22 +0000586 p = subprocess.Popen([sys.executable, "-Wd", "-c", code],
Antoine Pitrou696e0352010-08-08 22:18:46 +0000587 stdout=subprocess.PIPE,
588 stderr=subprocess.PIPE)
589 stdout, stderr = p.communicate()
Brian Curtin8291af22010-11-01 16:40:17 +0000590 p.stdout.close()
591 p.stderr.close()
Antoine Pitrou696e0352010-08-08 22:18:46 +0000592 self.assertEqual(p.returncode, 0)
593 self.assertEqual(stdout.strip(), b"")
594 return strip_python_stderr(stderr)
595
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000596 stderr = run_command(code % "0")
Georg Brandl08be72d2010-10-24 15:11:22 +0000597 self.assertIn(b"ResourceWarning: gc: 2 uncollectable objects at "
598 b"shutdown; use", stderr)
Antoine Pitrouaee47562010-09-16 15:04:49 +0000599 self.assertNotIn(b"<X 'first'>", stderr)
Antoine Pitrou696e0352010-08-08 22:18:46 +0000600 # With DEBUG_UNCOLLECTABLE, the garbage list gets printed
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000601 stderr = run_command(code % "gc.DEBUG_UNCOLLECTABLE")
Georg Brandl08be72d2010-10-24 15:11:22 +0000602 self.assertIn(b"ResourceWarning: gc: 2 uncollectable objects at "
603 b"shutdown", stderr)
Antoine Pitrouaee47562010-09-16 15:04:49 +0000604 self.assertTrue(
605 (b"[<X 'first'>, <X 'second'>]" in stderr) or
606 (b"[<X 'second'>, <X 'first'>]" in stderr), stderr)
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000607 # With DEBUG_SAVEALL, no additional message should get printed
608 # (because gc.garbage also contains normally reclaimable cyclic
609 # references, and its elements get printed at runtime anyway).
610 stderr = run_command(code % "gc.DEBUG_SAVEALL")
611 self.assertNotIn(b"uncollectable objects at shutdown", stderr)
612
Antoine Pitrou696e0352010-08-08 22:18:46 +0000613
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000614class GCCallbackTests(unittest.TestCase):
615 def setUp(self):
616 # Save gc state and disable it.
617 self.enabled = gc.isenabled()
618 gc.disable()
619 self.debug = gc.get_debug()
620 gc.set_debug(0)
621 gc.callbacks.append(self.cb1)
622 gc.callbacks.append(self.cb2)
Antoine Pitrou6b64fc62012-04-16 21:29:02 +0200623 self.othergarbage = []
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000624
625 def tearDown(self):
626 # Restore gc state
627 del self.visit
628 gc.callbacks.remove(self.cb1)
629 gc.callbacks.remove(self.cb2)
630 gc.set_debug(self.debug)
631 if self.enabled:
632 gc.enable()
633 # destroy any uncollectables
634 gc.collect()
635 for obj in gc.garbage:
636 if isinstance(obj, Uncollectable):
637 obj.partner = None
638 del gc.garbage[:]
Antoine Pitrou6b64fc62012-04-16 21:29:02 +0200639 del self.othergarbage
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000640 gc.collect()
641
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000642 def preclean(self):
643 # Remove all fluff from the system. Invoke this function
644 # manually rather than through self.setUp() for maximum
645 # safety.
646 self.visit = []
647 gc.collect()
648 garbage, gc.garbage[:] = gc.garbage[:], []
649 self.othergarbage.append(garbage)
650 self.visit = []
651
652 def cb1(self, phase, info):
653 self.visit.append((1, phase, dict(info)))
654
655 def cb2(self, phase, info):
656 self.visit.append((2, phase, dict(info)))
657 if phase == "stop" and hasattr(self, "cleanup"):
658 # Clean Uncollectable from garbage
659 uc = [e for e in gc.garbage if isinstance(e, Uncollectable)]
660 gc.garbage[:] = [e for e in gc.garbage
661 if not isinstance(e, Uncollectable)]
662 for e in uc:
663 e.partner = None
664
Antoine Pitroude3c73b2012-04-16 21:29:58 +0200665 def test_collect(self):
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000666 self.preclean()
667 gc.collect()
668 # Algorithmically verify the contents of self.visit
669 # because it is long and tortuous.
670
671 # Count the number of visits to each callback
672 n = [v[0] for v in self.visit]
673 n1 = [i for i in n if i == 1]
674 n2 = [i for i in n if i == 2]
675 self.assertEqual(n1, [1]*2)
676 self.assertEqual(n2, [2]*2)
677
678 # Count that we got the right number of start and stop callbacks.
679 n = [v[1] for v in self.visit]
680 n1 = [i for i in n if i == "start"]
681 n2 = [i for i in n if i == "stop"]
682 self.assertEqual(n1, ["start"]*2)
683 self.assertEqual(n2, ["stop"]*2)
684
685 # Check that we got the right info dict for all callbacks
686 for v in self.visit:
687 info = v[2]
688 self.assertTrue("generation" in info)
689 self.assertTrue("collected" in info)
690 self.assertTrue("uncollectable" in info)
691
Antoine Pitroude3c73b2012-04-16 21:29:58 +0200692 def test_collect_generation(self):
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000693 self.preclean()
694 gc.collect(2)
695 for v in self.visit:
696 info = v[2]
697 self.assertEqual(info["generation"], 2)
698
Antoine Pitroude3c73b2012-04-16 21:29:58 +0200699 def test_collect_garbage(self):
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000700 self.preclean()
701 # Each of these cause four objects to be garbage: Two
702 # Uncolectables and their instance dicts.
703 Uncollectable()
704 Uncollectable()
705 C1055820(666)
706 gc.collect()
707 for v in self.visit:
708 if v[1] != "stop":
709 continue
710 info = v[2]
711 self.assertEqual(info["collected"], 2)
712 self.assertEqual(info["uncollectable"], 8)
713
714 # We should now have the Uncollectables in gc.garbage
715 self.assertEqual(len(gc.garbage), 4)
716 for e in gc.garbage:
717 self.assertIsInstance(e, Uncollectable)
718
719 # Now, let our callback handle the Uncollectable instances
720 self.cleanup=True
721 self.visit = []
722 gc.garbage[:] = []
723 gc.collect()
724 for v in self.visit:
725 if v[1] != "stop":
726 continue
727 info = v[2]
728 self.assertEqual(info["collected"], 0)
729 self.assertEqual(info["uncollectable"], 4)
730
731 # Uncollectables should be gone
732 self.assertEqual(len(gc.garbage), 0)
733
734
Guido van Rossumd8faa362007-04-27 19:54:29 +0000735class GCTogglingTests(unittest.TestCase):
736 def setUp(self):
737 gc.enable()
738
739 def tearDown(self):
740 gc.disable()
741
742 def test_bug1055820c(self):
743 # Corresponds to temp2c.py in the bug report. This is pretty
744 # elaborate.
745
746 c0 = C1055820(0)
747 # Move c0 into generation 2.
748 gc.collect()
749
750 c1 = C1055820(1)
751 c1.keep_c0_alive = c0
752 del c0.loop # now only c1 keeps c0 alive
753
754 c2 = C1055820(2)
755 c2wr = weakref.ref(c2) # no callback!
756
757 ouch = []
758 def callback(ignored):
Tim Petersead8b7a2004-10-30 23:09:22 +0000759 ouch[:] = [c2wr()]
760
Guido van Rossumd8faa362007-04-27 19:54:29 +0000761 # The callback gets associated with a wr on an object in generation 2.
762 c0wr = weakref.ref(c0, callback)
Tim Petersead8b7a2004-10-30 23:09:22 +0000763
Guido van Rossumd8faa362007-04-27 19:54:29 +0000764 c0 = c1 = c2 = None
Tim Petersead8b7a2004-10-30 23:09:22 +0000765
Guido van Rossumd8faa362007-04-27 19:54:29 +0000766 # What we've set up: c0, c1, and c2 are all trash now. c0 is in
767 # generation 2. The only thing keeping it alive is that c1 points to
768 # it. c1 and c2 are in generation 0, and are in self-loops. There's a
769 # global weakref to c2 (c2wr), but that weakref has no callback.
770 # There's also a global weakref to c0 (c0wr), and that does have a
771 # callback, and that callback references c2 via c2wr().
772 #
773 # c0 has a wr with callback, which references c2wr
774 # ^
775 # |
776 # | Generation 2 above dots
777 #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .
778 # | Generation 0 below dots
779 # |
780 # |
781 # ^->c1 ^->c2 has a wr but no callback
782 # | | | |
783 # <--v <--v
784 #
785 # So this is the nightmare: when generation 0 gets collected, we see
786 # that c2 has a callback-free weakref, and c1 doesn't even have a
787 # weakref. Collecting generation 0 doesn't see c0 at all, and c0 is
788 # the only object that has a weakref with a callback. gc clears c1
789 # and c2. Clearing c1 has the side effect of dropping the refcount on
790 # c0 to 0, so c0 goes away (despite that it's in an older generation)
791 # and c0's wr callback triggers. That in turn materializes a reference
792 # to c2 via c2wr(), but c2 gets cleared anyway by gc.
Tim Petersead8b7a2004-10-30 23:09:22 +0000793
Guido van Rossumd8faa362007-04-27 19:54:29 +0000794 # We want to let gc happen "naturally", to preserve the distinction
795 # between generations.
796 junk = []
797 i = 0
798 detector = GC_Detector()
799 while not detector.gc_happened:
800 i += 1
801 if i > 10000:
802 self.fail("gc didn't happen after 10000 iterations")
803 self.assertEqual(len(ouch), 0)
804 junk.append([]) # this will eventually trigger gc
Tim Petersead8b7a2004-10-30 23:09:22 +0000805
Guido van Rossumd8faa362007-04-27 19:54:29 +0000806 self.assertEqual(len(ouch), 1) # else the callback wasn't invoked
807 for x in ouch:
808 # If the callback resurrected c2, the instance would be damaged,
809 # with an empty __dict__.
810 self.assertEqual(x, None)
Tim Petersead8b7a2004-10-30 23:09:22 +0000811
Guido van Rossumd8faa362007-04-27 19:54:29 +0000812 def test_bug1055820d(self):
813 # Corresponds to temp2d.py in the bug report. This is very much like
814 # test_bug1055820c, but uses a __del__ method instead of a weakref
815 # callback to sneak in a resurrection of cyclic trash.
Tim Petersead8b7a2004-10-30 23:09:22 +0000816
Guido van Rossumd8faa362007-04-27 19:54:29 +0000817 ouch = []
818 class D(C1055820):
819 def __del__(self):
820 ouch[:] = [c2wr()]
Tim Petersead8b7a2004-10-30 23:09:22 +0000821
Guido van Rossumd8faa362007-04-27 19:54:29 +0000822 d0 = D(0)
823 # Move all the above into generation 2.
824 gc.collect()
Tim Petersead8b7a2004-10-30 23:09:22 +0000825
Guido van Rossumd8faa362007-04-27 19:54:29 +0000826 c1 = C1055820(1)
827 c1.keep_d0_alive = d0
828 del d0.loop # now only c1 keeps d0 alive
Tim Petersead8b7a2004-10-30 23:09:22 +0000829
Guido van Rossumd8faa362007-04-27 19:54:29 +0000830 c2 = C1055820(2)
831 c2wr = weakref.ref(c2) # no callback!
Tim Petersead8b7a2004-10-30 23:09:22 +0000832
Guido van Rossumd8faa362007-04-27 19:54:29 +0000833 d0 = c1 = c2 = None
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000834
Guido van Rossumd8faa362007-04-27 19:54:29 +0000835 # What we've set up: d0, c1, and c2 are all trash now. d0 is in
836 # generation 2. The only thing keeping it alive is that c1 points to
837 # it. c1 and c2 are in generation 0, and are in self-loops. There's
838 # a global weakref to c2 (c2wr), but that weakref has no callback.
839 # There are no other weakrefs.
840 #
841 # d0 has a __del__ method that references c2wr
842 # ^
843 # |
844 # | Generation 2 above dots
845 #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .
846 # | Generation 0 below dots
847 # |
848 # |
849 # ^->c1 ^->c2 has a wr but no callback
850 # | | | |
851 # <--v <--v
852 #
853 # So this is the nightmare: when generation 0 gets collected, we see
854 # that c2 has a callback-free weakref, and c1 doesn't even have a
855 # weakref. Collecting generation 0 doesn't see d0 at all. gc clears
856 # c1 and c2. Clearing c1 has the side effect of dropping the refcount
857 # on d0 to 0, so d0 goes away (despite that it's in an older
858 # generation) and d0's __del__ triggers. That in turn materializes
859 # a reference to c2 via c2wr(), but c2 gets cleared anyway by gc.
860
861 # We want to let gc happen "naturally", to preserve the distinction
862 # between generations.
863 detector = GC_Detector()
864 junk = []
865 i = 0
866 while not detector.gc_happened:
867 i += 1
868 if i > 10000:
869 self.fail("gc didn't happen after 10000 iterations")
870 self.assertEqual(len(ouch), 0)
871 junk.append([]) # this will eventually trigger gc
872
873 self.assertEqual(len(ouch), 1) # else __del__ wasn't invoked
874 for x in ouch:
875 # If __del__ resurrected c2, the instance would be damaged, with an
876 # empty __dict__.
877 self.assertEqual(x, None)
878
879def test_main():
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000880 enabled = gc.isenabled()
881 gc.disable()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000882 assert not gc.isenabled()
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000883 debug = gc.get_debug()
884 gc.set_debug(debug & ~gc.DEBUG_LEAK) # this test is supposed to leak
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000885
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000886 try:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000887 gc.collect() # Delete 2nd generation garbage
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000888 run_unittest(GCTests, GCTogglingTests, GCCallbackTests)
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000889 finally:
890 gc.set_debug(debug)
891 # test gc.enable() even if GC is disabled by default
892 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000893 print("restoring automatic collection")
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000894 # make sure to always test gc.enable()
895 gc.enable()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000896 assert gc.isenabled()
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000897 if not enabled:
898 gc.disable()
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000899
Guido van Rossumd8faa362007-04-27 19:54:29 +0000900if __name__ == "__main__":
901 test_main()