blob: 6b52e5a66e0ee512fd12359e2a90311df773c02d [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)
Antoine Pitrou5f454a02013-05-06 21:15:57 +02004from test.script_helper import assert_python_ok, make_script, temp_dir
5
Neil Schemenauer88c761a2001-07-12 13:25:53 +00006import sys
Antoine Pitrou2b0218a2012-09-06 00:59:49 +02007import time
Jeremy Hyltonc5007aa2000-06-30 05:02:53 +00008import gc
Tim Petersead8b7a2004-10-30 23:09:22 +00009import weakref
Jeremy Hyltonc5007aa2000-06-30 05:02:53 +000010
Antoine Pitrou2b0218a2012-09-06 00:59:49 +020011try:
12 import threading
13except ImportError:
14 threading = None
15
Guido van Rossumd8faa362007-04-27 19:54:29 +000016### Support code
17###############################################################################
Tim Peters0f81ab62003-04-08 16:39:48 +000018
Tim Petersead8b7a2004-10-30 23:09:22 +000019# Bug 1055820 has several tests of longstanding bugs involving weakrefs and
20# cyclic gc.
21
22# An instance of C1055820 has a self-loop, so becomes cyclic trash when
23# unreachable.
24class C1055820(object):
25 def __init__(self, i):
26 self.i = i
27 self.loop = self
28
29class GC_Detector(object):
30 # Create an instance I. Then gc hasn't happened again so long as
31 # I.gc_happened is false.
32
33 def __init__(self):
34 self.gc_happened = False
35
36 def it_happened(ignored):
37 self.gc_happened = True
38
39 # Create a piece of cyclic trash that triggers it_happened when
40 # gc collects it.
41 self.wr = weakref.ref(C1055820(666), it_happened)
42
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +000043class Uncollectable(object):
44 """Create a reference cycle with multiple __del__ methods.
45
46 An object in a reference cycle will never have zero references,
47 and so must be garbage collected. If one or more objects in the
48 cycle have __del__ methods, the gc refuses to guess an order,
49 and leaves the cycle uncollected."""
50 def __init__(self, partner=None):
51 if partner is None:
52 self.partner = Uncollectable(partner=self)
53 else:
54 self.partner = partner
55 def __del__(self):
56 pass
Tim Petersead8b7a2004-10-30 23:09:22 +000057
Guido van Rossumd8faa362007-04-27 19:54:29 +000058### Tests
59###############################################################################
Tim Petersead8b7a2004-10-30 23:09:22 +000060
Guido van Rossumd8faa362007-04-27 19:54:29 +000061class GCTests(unittest.TestCase):
62 def test_list(self):
63 l = []
64 l.append(l)
65 gc.collect()
66 del l
67 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +000068
Guido van Rossumd8faa362007-04-27 19:54:29 +000069 def test_dict(self):
70 d = {}
71 d[1] = d
72 gc.collect()
73 del d
74 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +000075
Guido van Rossumd8faa362007-04-27 19:54:29 +000076 def test_tuple(self):
77 # since tuples are immutable we close the loop with a list
78 l = []
79 t = (l,)
80 l.append(t)
81 gc.collect()
82 del t
83 del l
84 self.assertEqual(gc.collect(), 2)
Tim Petersead8b7a2004-10-30 23:09:22 +000085
Guido van Rossumd8faa362007-04-27 19:54:29 +000086 def test_class(self):
87 class A:
88 pass
89 A.a = A
90 gc.collect()
91 del A
92 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +000093
Guido van Rossumd8faa362007-04-27 19:54:29 +000094 def test_newstyleclass(self):
95 class A(object):
96 pass
97 gc.collect()
98 del A
99 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000100
Guido van Rossumd8faa362007-04-27 19:54:29 +0000101 def test_instance(self):
102 class A:
103 pass
104 a = A()
105 a.a = a
106 gc.collect()
107 del a
108 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000109
Guido van Rossumd8faa362007-04-27 19:54:29 +0000110 def test_newinstance(self):
111 class A(object):
112 pass
113 a = A()
114 a.a = a
115 gc.collect()
116 del a
117 self.assertNotEqual(gc.collect(), 0)
118 class B(list):
119 pass
120 class C(B, A):
121 pass
122 a = C()
123 a.a = a
124 gc.collect()
125 del a
126 self.assertNotEqual(gc.collect(), 0)
127 del B, C
128 self.assertNotEqual(gc.collect(), 0)
129 A.a = A()
130 del A
131 self.assertNotEqual(gc.collect(), 0)
132 self.assertEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000133
Guido van Rossumd8faa362007-04-27 19:54:29 +0000134 def test_method(self):
135 # Tricky: self.__init__ is a bound method, it references the instance.
136 class A:
137 def __init__(self):
138 self.init = self.__init__
139 a = A()
140 gc.collect()
141 del a
142 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000143
Guido van Rossumd8faa362007-04-27 19:54:29 +0000144 def test_finalizer(self):
145 # A() is uncollectable if it is part of a cycle, make sure it shows up
146 # in gc.garbage.
147 class A:
148 def __del__(self): pass
149 class B:
150 pass
151 a = A()
152 a.a = a
153 id_a = id(a)
154 b = B()
155 b.b = b
156 gc.collect()
157 del a
158 del b
159 self.assertNotEqual(gc.collect(), 0)
160 for obj in gc.garbage:
161 if id(obj) == id_a:
162 del obj.a
163 break
164 else:
165 self.fail("didn't find obj in garbage (finalizer)")
166 gc.garbage.remove(obj)
Tim Petersead8b7a2004-10-30 23:09:22 +0000167
Guido van Rossumd8faa362007-04-27 19:54:29 +0000168 def test_finalizer_newclass(self):
169 # A() is uncollectable if it is part of a cycle, make sure it shows up
170 # in gc.garbage.
171 class A(object):
172 def __del__(self): pass
173 class B(object):
174 pass
175 a = A()
176 a.a = a
177 id_a = id(a)
178 b = B()
179 b.b = b
180 gc.collect()
181 del a
182 del b
183 self.assertNotEqual(gc.collect(), 0)
184 for obj in gc.garbage:
185 if id(obj) == id_a:
186 del obj.a
187 break
188 else:
189 self.fail("didn't find obj in garbage (finalizer)")
190 gc.garbage.remove(obj)
Tim Petersead8b7a2004-10-30 23:09:22 +0000191
Guido van Rossumd8faa362007-04-27 19:54:29 +0000192 def test_function(self):
193 # Tricky: f -> d -> f, code should call d.clear() after the exec to
194 # break the cycle.
195 d = {}
196 exec("def f(): pass\n", d)
197 gc.collect()
198 del d
199 self.assertEqual(gc.collect(), 2)
Tim Petersead8b7a2004-10-30 23:09:22 +0000200
Brett Cannon7a540732011-02-22 03:04:06 +0000201 @refcount_test
Guido van Rossumd8faa362007-04-27 19:54:29 +0000202 def test_frame(self):
203 def f():
204 frame = sys._getframe()
205 gc.collect()
206 f()
207 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +0000208
Guido van Rossumd8faa362007-04-27 19:54:29 +0000209 def test_saveall(self):
210 # Verify that cyclic garbage like lists show up in gc.garbage if the
211 # SAVEALL option is enabled.
Tim Petersead8b7a2004-10-30 23:09:22 +0000212
Guido van Rossumd8faa362007-04-27 19:54:29 +0000213 # First make sure we don't save away other stuff that just happens to
214 # be waiting for collection.
215 gc.collect()
216 # if this fails, someone else created immortal trash
217 self.assertEqual(gc.garbage, [])
218
219 L = []
220 L.append(L)
221 id_L = id(L)
222
223 debug = gc.get_debug()
224 gc.set_debug(debug | gc.DEBUG_SAVEALL)
225 del L
226 gc.collect()
227 gc.set_debug(debug)
228
229 self.assertEqual(len(gc.garbage), 1)
230 obj = gc.garbage.pop()
231 self.assertEqual(id(obj), id_L)
232
233 def test_del(self):
234 # __del__ methods can trigger collection, make this to happen
235 thresholds = gc.get_threshold()
236 gc.enable()
237 gc.set_threshold(1)
238
239 class A:
240 def __del__(self):
241 dir(self)
242 a = A()
243 del a
244
245 gc.disable()
246 gc.set_threshold(*thresholds)
247
248 def test_del_newclass(self):
249 # __del__ methods can trigger collection, make this to happen
250 thresholds = gc.get_threshold()
251 gc.enable()
252 gc.set_threshold(1)
253
254 class A(object):
255 def __del__(self):
256 dir(self)
257 a = A()
258 del a
259
260 gc.disable()
261 gc.set_threshold(*thresholds)
262
Christian Heimesa156e092008-02-16 07:38:31 +0000263 # The following two tests are fragile:
264 # They precisely count the number of allocations,
265 # which is highly implementation-dependent.
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200266 # For example, disposed tuples are not freed, but reused.
267 # To minimize variations, though, we first store the get_count() results
268 # and check them at the end.
Brett Cannon7a540732011-02-22 03:04:06 +0000269 @refcount_test
Guido van Rossumd8faa362007-04-27 19:54:29 +0000270 def test_get_count(self):
271 gc.collect()
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200272 a, b, c = gc.get_count()
273 x = []
274 d, e, f = gc.get_count()
275 self.assertEqual((b, c), (0, 0))
276 self.assertEqual((e, f), (0, 0))
277 # This is less fragile than asserting that a equals 0.
278 self.assertLess(a, 5)
279 # Between the two calls to get_count(), at least one object was
280 # created (the list).
281 self.assertGreater(d, a)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000282
Brett Cannon7a540732011-02-22 03:04:06 +0000283 @refcount_test
Guido van Rossumd8faa362007-04-27 19:54:29 +0000284 def test_collect_generations(self):
285 gc.collect()
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200286 # This object will "trickle" into generation N + 1 after
287 # each call to collect(N)
288 x = []
Guido van Rossumd8faa362007-04-27 19:54:29 +0000289 gc.collect(0)
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200290 # x is now in gen 1
291 a, b, c = gc.get_count()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000292 gc.collect(1)
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200293 # x is now in gen 2
294 d, e, f = gc.get_count()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000295 gc.collect(2)
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200296 # x is now in gen 3
297 g, h, i = gc.get_count()
298 # We don't check a, d, g since their exact values depends on
299 # internal implementation details of the interpreter.
300 self.assertEqual((b, c), (1, 0))
301 self.assertEqual((e, f), (0, 1))
302 self.assertEqual((h, i), (0, 0))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000303
304 def test_trashcan(self):
305 class Ouch:
306 n = 0
307 def __del__(self):
308 Ouch.n = Ouch.n + 1
309 if Ouch.n % 17 == 0:
310 gc.collect()
311
312 # "trashcan" is a hack to prevent stack overflow when deallocating
313 # very deeply nested tuples etc. It works in part by abusing the
314 # type pointer and refcount fields, and that can yield horrible
315 # problems when gc tries to traverse the structures.
316 # If this test fails (as it does in 2.0, 2.1 and 2.2), it will
317 # most likely die via segfault.
318
319 # Note: In 2.3 the possibility for compiling without cyclic gc was
320 # removed, and that in turn allows the trashcan mechanism to work
321 # via much simpler means (e.g., it never abuses the type pointer or
322 # refcount fields anymore). Since it's much less likely to cause a
323 # problem now, the various constants in this expensive (we force a lot
324 # of full collections) test are cut back from the 2.2 version.
325 gc.enable()
326 N = 150
327 for count in range(2):
328 t = []
329 for i in range(N):
330 t = [t, Ouch()]
331 u = []
332 for i in range(N):
333 u = [u, Ouch()]
334 v = {}
335 for i in range(N):
336 v = {1: v, 2: Ouch()}
337 gc.disable()
338
Antoine Pitrou2b0218a2012-09-06 00:59:49 +0200339 @unittest.skipUnless(threading, "test meaningless on builds without threads")
340 def test_trashcan_threads(self):
341 # Issue #13992: trashcan mechanism should be thread-safe
342 NESTING = 60
343 N_THREADS = 2
344
345 def sleeper_gen():
346 """A generator that releases the GIL when closed or dealloc'ed."""
347 try:
348 yield
349 finally:
350 time.sleep(0.000001)
351
352 class C(list):
353 # Appending to a list is atomic, which avoids the use of a lock.
354 inits = []
355 dels = []
356 def __init__(self, alist):
357 self[:] = alist
358 C.inits.append(None)
359 def __del__(self):
360 # This __del__ is called by subtype_dealloc().
361 C.dels.append(None)
362 # `g` will release the GIL when garbage-collected. This
363 # helps assert subtype_dealloc's behaviour when threads
364 # switch in the middle of it.
365 g = sleeper_gen()
366 next(g)
367 # Now that __del__ is finished, subtype_dealloc will proceed
368 # to call list_dealloc, which also uses the trashcan mechanism.
369
370 def make_nested():
371 """Create a sufficiently nested container object so that the
372 trashcan mechanism is invoked when deallocating it."""
373 x = C([])
374 for i in range(NESTING):
375 x = [C([x])]
376 del x
377
378 def run_thread():
379 """Exercise make_nested() in a loop."""
380 while not exit:
381 make_nested()
382
383 old_switchinterval = sys.getswitchinterval()
384 sys.setswitchinterval(1e-5)
385 try:
386 exit = False
387 threads = []
388 for i in range(N_THREADS):
389 t = threading.Thread(target=run_thread)
390 threads.append(t)
391 for t in threads:
392 t.start()
393 time.sleep(1.0)
394 exit = True
395 for t in threads:
396 t.join()
397 finally:
398 sys.setswitchinterval(old_switchinterval)
399 gc.collect()
400 self.assertEqual(len(C.inits), len(C.dels))
401
Guido van Rossumd8faa362007-04-27 19:54:29 +0000402 def test_boom(self):
403 class Boom:
404 def __getattr__(self, someattribute):
405 del self.attr
406 raise AttributeError
407
408 a = Boom()
409 b = Boom()
410 a.attr = b
411 b.attr = a
412
413 gc.collect()
414 garbagelen = len(gc.garbage)
415 del a, b
416 # a<->b are in a trash cycle now. Collection will invoke
417 # Boom.__getattr__ (to see whether a and b have __del__ methods), and
418 # __getattr__ deletes the internal "attr" attributes as a side effect.
419 # That causes the trash cycle to get reclaimed via refcounts falling to
420 # 0, thus mutating the trash graph as a side effect of merely asking
421 # whether __del__ exists. This used to (before 2.3b1) crash Python.
422 # Now __getattr__ isn't called.
423 self.assertEqual(gc.collect(), 4)
424 self.assertEqual(len(gc.garbage), garbagelen)
425
426 def test_boom2(self):
427 class Boom2:
428 def __init__(self):
429 self.x = 0
430
431 def __getattr__(self, someattribute):
432 self.x += 1
433 if self.x > 1:
434 del self.attr
435 raise AttributeError
436
437 a = Boom2()
438 b = Boom2()
439 a.attr = b
440 b.attr = a
441
442 gc.collect()
443 garbagelen = len(gc.garbage)
444 del a, b
445 # Much like test_boom(), except that __getattr__ doesn't break the
446 # cycle until the second time gc checks for __del__. As of 2.3b1,
447 # there isn't a second time, so this simply cleans up the trash cycle.
448 # We expect a, b, a.__dict__ and b.__dict__ (4 objects) to get
449 # reclaimed this way.
450 self.assertEqual(gc.collect(), 4)
451 self.assertEqual(len(gc.garbage), garbagelen)
452
453 def test_boom_new(self):
454 # boom__new and boom2_new are exactly like boom and boom2, except use
455 # new-style classes.
456
457 class Boom_New(object):
458 def __getattr__(self, someattribute):
459 del self.attr
460 raise AttributeError
461
462 a = Boom_New()
463 b = Boom_New()
464 a.attr = b
465 b.attr = a
466
467 gc.collect()
468 garbagelen = len(gc.garbage)
469 del a, b
470 self.assertEqual(gc.collect(), 4)
471 self.assertEqual(len(gc.garbage), garbagelen)
472
473 def test_boom2_new(self):
474 class Boom2_New(object):
475 def __init__(self):
476 self.x = 0
477
478 def __getattr__(self, someattribute):
479 self.x += 1
480 if self.x > 1:
481 del self.attr
482 raise AttributeError
483
484 a = Boom2_New()
485 b = Boom2_New()
486 a.attr = b
487 b.attr = a
488
489 gc.collect()
490 garbagelen = len(gc.garbage)
491 del a, b
492 self.assertEqual(gc.collect(), 4)
493 self.assertEqual(len(gc.garbage), garbagelen)
494
495 def test_get_referents(self):
496 alist = [1, 3, 5]
497 got = gc.get_referents(alist)
498 got.sort()
499 self.assertEqual(got, alist)
500
501 atuple = tuple(alist)
502 got = gc.get_referents(atuple)
503 got.sort()
504 self.assertEqual(got, alist)
505
506 adict = {1: 3, 5: 7}
507 expected = [1, 3, 5, 7]
508 got = gc.get_referents(adict)
509 got.sort()
510 self.assertEqual(got, expected)
511
512 got = gc.get_referents([1, 2], {3: 4}, (0, 0, 0))
513 got.sort()
Guido van Rossum805365e2007-05-07 22:24:25 +0000514 self.assertEqual(got, [0, 0] + list(range(5)))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000515
516 self.assertEqual(gc.get_referents(1, 'a', 4j), [])
517
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000518 def test_is_tracked(self):
519 # Atomic built-in types are not tracked, user-defined objects and
520 # mutable containers are.
521 # NOTE: types with special optimizations (e.g. tuple) have tests
522 # in their own test files instead.
523 self.assertFalse(gc.is_tracked(None))
524 self.assertFalse(gc.is_tracked(1))
525 self.assertFalse(gc.is_tracked(1.0))
526 self.assertFalse(gc.is_tracked(1.0 + 5.0j))
527 self.assertFalse(gc.is_tracked(True))
528 self.assertFalse(gc.is_tracked(False))
529 self.assertFalse(gc.is_tracked(b"a"))
530 self.assertFalse(gc.is_tracked("a"))
531 self.assertFalse(gc.is_tracked(bytearray(b"a")))
532 self.assertFalse(gc.is_tracked(type))
533 self.assertFalse(gc.is_tracked(int))
534 self.assertFalse(gc.is_tracked(object))
535 self.assertFalse(gc.is_tracked(object()))
536
537 class UserClass:
538 pass
539 self.assertTrue(gc.is_tracked(gc))
540 self.assertTrue(gc.is_tracked(UserClass))
541 self.assertTrue(gc.is_tracked(UserClass()))
542 self.assertTrue(gc.is_tracked([]))
543 self.assertTrue(gc.is_tracked(set()))
544
Guido van Rossumd8faa362007-04-27 19:54:29 +0000545 def test_bug1055820b(self):
546 # Corresponds to temp2b.py in the bug report.
547
548 ouch = []
549 def callback(ignored):
550 ouch[:] = [wr() for wr in WRs]
551
552 Cs = [C1055820(i) for i in range(2)]
553 WRs = [weakref.ref(c, callback) for c in Cs]
554 c = None
555
556 gc.collect()
557 self.assertEqual(len(ouch), 0)
558 # Make the two instances trash, and collect again. The bug was that
559 # the callback materialized a strong reference to an instance, but gc
560 # cleared the instance's dict anyway.
561 Cs = None
562 gc.collect()
563 self.assertEqual(len(ouch), 2) # else the callbacks didn't run
564 for x in ouch:
565 # If the callback resurrected one of these guys, the instance
566 # would be damaged, with an empty __dict__.
567 self.assertEqual(x, None)
568
Antoine Pitrou696e0352010-08-08 22:18:46 +0000569 def test_garbage_at_shutdown(self):
570 import subprocess
571 code = """if 1:
572 import gc
573 class X:
574 def __init__(self, name):
575 self.name = name
576 def __repr__(self):
577 return "<X %%r>" %% self.name
578 def __del__(self):
579 pass
580
581 x = X('first')
582 x.x = x
583 x.y = X('second')
584 del x
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000585 gc.set_debug(%s)
Antoine Pitrou696e0352010-08-08 22:18:46 +0000586 """
587 def run_command(code):
Georg Brandl08be72d2010-10-24 15:11:22 +0000588 p = subprocess.Popen([sys.executable, "-Wd", "-c", code],
Antoine Pitrou696e0352010-08-08 22:18:46 +0000589 stdout=subprocess.PIPE,
590 stderr=subprocess.PIPE)
591 stdout, stderr = p.communicate()
Brian Curtin8291af22010-11-01 16:40:17 +0000592 p.stdout.close()
593 p.stderr.close()
Antoine Pitrou696e0352010-08-08 22:18:46 +0000594 self.assertEqual(p.returncode, 0)
595 self.assertEqual(stdout.strip(), b"")
596 return strip_python_stderr(stderr)
597
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000598 stderr = run_command(code % "0")
Georg Brandl08be72d2010-10-24 15:11:22 +0000599 self.assertIn(b"ResourceWarning: gc: 2 uncollectable objects at "
600 b"shutdown; use", stderr)
Antoine Pitrouaee47562010-09-16 15:04:49 +0000601 self.assertNotIn(b"<X 'first'>", stderr)
Antoine Pitrou696e0352010-08-08 22:18:46 +0000602 # With DEBUG_UNCOLLECTABLE, the garbage list gets printed
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000603 stderr = run_command(code % "gc.DEBUG_UNCOLLECTABLE")
Georg Brandl08be72d2010-10-24 15:11:22 +0000604 self.assertIn(b"ResourceWarning: gc: 2 uncollectable objects at "
605 b"shutdown", stderr)
Antoine Pitrouaee47562010-09-16 15:04:49 +0000606 self.assertTrue(
607 (b"[<X 'first'>, <X 'second'>]" in stderr) or
608 (b"[<X 'second'>, <X 'first'>]" in stderr), stderr)
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000609 # With DEBUG_SAVEALL, no additional message should get printed
610 # (because gc.garbage also contains normally reclaimable cyclic
611 # references, and its elements get printed at runtime anyway).
612 stderr = run_command(code % "gc.DEBUG_SAVEALL")
613 self.assertNotIn(b"uncollectable objects at shutdown", stderr)
614
Antoine Pitrou5f454a02013-05-06 21:15:57 +0200615 def test_gc_main_module_at_shutdown(self):
616 # Create a reference cycle through the __main__ module and check
617 # it gets collected at interpreter shutdown.
618 code = """if 1:
619 import weakref
620 class C:
621 def __del__(self):
622 print('__del__ called')
623 l = [C()]
624 l.append(l)
625 """
626 rc, out, err = assert_python_ok('-c', code)
627 self.assertEqual(out.strip(), b'__del__ called')
628
629 def test_gc_ordinary_module_at_shutdown(self):
630 # Same as above, but with a non-__main__ module.
631 with temp_dir() as script_dir:
632 module = """if 1:
633 import weakref
634 class C:
635 def __del__(self):
636 print('__del__ called')
637 l = [C()]
638 l.append(l)
639 """
640 code = """if 1:
641 import sys
642 sys.path.insert(0, %r)
643 import gctest
644 """ % (script_dir,)
645 make_script(script_dir, 'gctest', module)
646 rc, out, err = assert_python_ok('-c', code)
647 self.assertEqual(out.strip(), b'__del__ called')
648
Antoine Pitroud4156c12012-10-30 22:43:19 +0100649 def test_get_stats(self):
650 stats = gc.get_stats()
651 self.assertEqual(len(stats), 3)
652 for st in stats:
653 self.assertIsInstance(st, dict)
654 self.assertEqual(set(st),
655 {"collected", "collections", "uncollectable"})
656 self.assertGreaterEqual(st["collected"], 0)
657 self.assertGreaterEqual(st["collections"], 0)
658 self.assertGreaterEqual(st["uncollectable"], 0)
659 # Check that collection counts are incremented correctly
660 if gc.isenabled():
661 self.addCleanup(gc.enable)
662 gc.disable()
663 old = gc.get_stats()
664 gc.collect(0)
665 new = gc.get_stats()
666 self.assertEqual(new[0]["collections"], old[0]["collections"] + 1)
667 self.assertEqual(new[1]["collections"], old[1]["collections"])
668 self.assertEqual(new[2]["collections"], old[2]["collections"])
669 gc.collect(2)
670 new = gc.get_stats()
671 self.assertEqual(new[0]["collections"], old[0]["collections"] + 1)
672 self.assertEqual(new[1]["collections"], old[1]["collections"])
673 self.assertEqual(new[2]["collections"], old[2]["collections"] + 1)
674
Antoine Pitrou696e0352010-08-08 22:18:46 +0000675
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000676class GCCallbackTests(unittest.TestCase):
677 def setUp(self):
678 # Save gc state and disable it.
679 self.enabled = gc.isenabled()
680 gc.disable()
681 self.debug = gc.get_debug()
682 gc.set_debug(0)
683 gc.callbacks.append(self.cb1)
684 gc.callbacks.append(self.cb2)
Antoine Pitrou6b64fc62012-04-16 21:29:02 +0200685 self.othergarbage = []
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000686
687 def tearDown(self):
688 # Restore gc state
689 del self.visit
690 gc.callbacks.remove(self.cb1)
691 gc.callbacks.remove(self.cb2)
692 gc.set_debug(self.debug)
693 if self.enabled:
694 gc.enable()
695 # destroy any uncollectables
696 gc.collect()
697 for obj in gc.garbage:
698 if isinstance(obj, Uncollectable):
699 obj.partner = None
700 del gc.garbage[:]
Antoine Pitrou6b64fc62012-04-16 21:29:02 +0200701 del self.othergarbage
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000702 gc.collect()
703
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000704 def preclean(self):
705 # Remove all fluff from the system. Invoke this function
706 # manually rather than through self.setUp() for maximum
707 # safety.
708 self.visit = []
709 gc.collect()
710 garbage, gc.garbage[:] = gc.garbage[:], []
711 self.othergarbage.append(garbage)
712 self.visit = []
713
714 def cb1(self, phase, info):
715 self.visit.append((1, phase, dict(info)))
716
717 def cb2(self, phase, info):
718 self.visit.append((2, phase, dict(info)))
719 if phase == "stop" and hasattr(self, "cleanup"):
720 # Clean Uncollectable from garbage
721 uc = [e for e in gc.garbage if isinstance(e, Uncollectable)]
722 gc.garbage[:] = [e for e in gc.garbage
723 if not isinstance(e, Uncollectable)]
724 for e in uc:
725 e.partner = None
726
Antoine Pitroude3c73b2012-04-16 21:29:58 +0200727 def test_collect(self):
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000728 self.preclean()
729 gc.collect()
730 # Algorithmically verify the contents of self.visit
731 # because it is long and tortuous.
732
733 # Count the number of visits to each callback
734 n = [v[0] for v in self.visit]
735 n1 = [i for i in n if i == 1]
736 n2 = [i for i in n if i == 2]
737 self.assertEqual(n1, [1]*2)
738 self.assertEqual(n2, [2]*2)
739
740 # Count that we got the right number of start and stop callbacks.
741 n = [v[1] for v in self.visit]
742 n1 = [i for i in n if i == "start"]
743 n2 = [i for i in n if i == "stop"]
744 self.assertEqual(n1, ["start"]*2)
745 self.assertEqual(n2, ["stop"]*2)
746
747 # Check that we got the right info dict for all callbacks
748 for v in self.visit:
749 info = v[2]
750 self.assertTrue("generation" in info)
751 self.assertTrue("collected" in info)
752 self.assertTrue("uncollectable" in info)
753
Antoine Pitroude3c73b2012-04-16 21:29:58 +0200754 def test_collect_generation(self):
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000755 self.preclean()
756 gc.collect(2)
757 for v in self.visit:
758 info = v[2]
759 self.assertEqual(info["generation"], 2)
760
Antoine Pitroude3c73b2012-04-16 21:29:58 +0200761 def test_collect_garbage(self):
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000762 self.preclean()
763 # Each of these cause four objects to be garbage: Two
764 # Uncolectables and their instance dicts.
765 Uncollectable()
766 Uncollectable()
767 C1055820(666)
768 gc.collect()
769 for v in self.visit:
770 if v[1] != "stop":
771 continue
772 info = v[2]
773 self.assertEqual(info["collected"], 2)
774 self.assertEqual(info["uncollectable"], 8)
775
776 # We should now have the Uncollectables in gc.garbage
777 self.assertEqual(len(gc.garbage), 4)
778 for e in gc.garbage:
779 self.assertIsInstance(e, Uncollectable)
780
781 # Now, let our callback handle the Uncollectable instances
782 self.cleanup=True
783 self.visit = []
784 gc.garbage[:] = []
785 gc.collect()
786 for v in self.visit:
787 if v[1] != "stop":
788 continue
789 info = v[2]
790 self.assertEqual(info["collected"], 0)
791 self.assertEqual(info["uncollectable"], 4)
792
793 # Uncollectables should be gone
794 self.assertEqual(len(gc.garbage), 0)
795
796
Guido van Rossumd8faa362007-04-27 19:54:29 +0000797class GCTogglingTests(unittest.TestCase):
798 def setUp(self):
799 gc.enable()
800
801 def tearDown(self):
802 gc.disable()
803
804 def test_bug1055820c(self):
805 # Corresponds to temp2c.py in the bug report. This is pretty
806 # elaborate.
807
808 c0 = C1055820(0)
809 # Move c0 into generation 2.
810 gc.collect()
811
812 c1 = C1055820(1)
813 c1.keep_c0_alive = c0
814 del c0.loop # now only c1 keeps c0 alive
815
816 c2 = C1055820(2)
817 c2wr = weakref.ref(c2) # no callback!
818
819 ouch = []
820 def callback(ignored):
Tim Petersead8b7a2004-10-30 23:09:22 +0000821 ouch[:] = [c2wr()]
822
Guido van Rossumd8faa362007-04-27 19:54:29 +0000823 # The callback gets associated with a wr on an object in generation 2.
824 c0wr = weakref.ref(c0, callback)
Tim Petersead8b7a2004-10-30 23:09:22 +0000825
Guido van Rossumd8faa362007-04-27 19:54:29 +0000826 c0 = c1 = c2 = None
Tim Petersead8b7a2004-10-30 23:09:22 +0000827
Guido van Rossumd8faa362007-04-27 19:54:29 +0000828 # What we've set up: c0, c1, and c2 are all trash now. c0 is in
829 # generation 2. The only thing keeping it alive is that c1 points to
830 # it. c1 and c2 are in generation 0, and are in self-loops. There's a
831 # global weakref to c2 (c2wr), but that weakref has no callback.
832 # There's also a global weakref to c0 (c0wr), and that does have a
833 # callback, and that callback references c2 via c2wr().
834 #
835 # c0 has a wr with callback, which references c2wr
836 # ^
837 # |
838 # | Generation 2 above dots
839 #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .
840 # | Generation 0 below dots
841 # |
842 # |
843 # ^->c1 ^->c2 has a wr but no callback
844 # | | | |
845 # <--v <--v
846 #
847 # So this is the nightmare: when generation 0 gets collected, we see
848 # that c2 has a callback-free weakref, and c1 doesn't even have a
849 # weakref. Collecting generation 0 doesn't see c0 at all, and c0 is
850 # the only object that has a weakref with a callback. gc clears c1
851 # and c2. Clearing c1 has the side effect of dropping the refcount on
852 # c0 to 0, so c0 goes away (despite that it's in an older generation)
853 # and c0's wr callback triggers. That in turn materializes a reference
854 # to c2 via c2wr(), but c2 gets cleared anyway by gc.
Tim Petersead8b7a2004-10-30 23:09:22 +0000855
Guido van Rossumd8faa362007-04-27 19:54:29 +0000856 # We want to let gc happen "naturally", to preserve the distinction
857 # between generations.
858 junk = []
859 i = 0
860 detector = GC_Detector()
861 while not detector.gc_happened:
862 i += 1
863 if i > 10000:
864 self.fail("gc didn't happen after 10000 iterations")
865 self.assertEqual(len(ouch), 0)
866 junk.append([]) # this will eventually trigger gc
Tim Petersead8b7a2004-10-30 23:09:22 +0000867
Guido van Rossumd8faa362007-04-27 19:54:29 +0000868 self.assertEqual(len(ouch), 1) # else the callback wasn't invoked
869 for x in ouch:
870 # If the callback resurrected c2, the instance would be damaged,
871 # with an empty __dict__.
872 self.assertEqual(x, None)
Tim Petersead8b7a2004-10-30 23:09:22 +0000873
Guido van Rossumd8faa362007-04-27 19:54:29 +0000874 def test_bug1055820d(self):
875 # Corresponds to temp2d.py in the bug report. This is very much like
876 # test_bug1055820c, but uses a __del__ method instead of a weakref
877 # callback to sneak in a resurrection of cyclic trash.
Tim Petersead8b7a2004-10-30 23:09:22 +0000878
Guido van Rossumd8faa362007-04-27 19:54:29 +0000879 ouch = []
880 class D(C1055820):
881 def __del__(self):
882 ouch[:] = [c2wr()]
Tim Petersead8b7a2004-10-30 23:09:22 +0000883
Guido van Rossumd8faa362007-04-27 19:54:29 +0000884 d0 = D(0)
885 # Move all the above into generation 2.
886 gc.collect()
Tim Petersead8b7a2004-10-30 23:09:22 +0000887
Guido van Rossumd8faa362007-04-27 19:54:29 +0000888 c1 = C1055820(1)
889 c1.keep_d0_alive = d0
890 del d0.loop # now only c1 keeps d0 alive
Tim Petersead8b7a2004-10-30 23:09:22 +0000891
Guido van Rossumd8faa362007-04-27 19:54:29 +0000892 c2 = C1055820(2)
893 c2wr = weakref.ref(c2) # no callback!
Tim Petersead8b7a2004-10-30 23:09:22 +0000894
Guido van Rossumd8faa362007-04-27 19:54:29 +0000895 d0 = c1 = c2 = None
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000896
Guido van Rossumd8faa362007-04-27 19:54:29 +0000897 # What we've set up: d0, c1, and c2 are all trash now. d0 is in
898 # generation 2. The only thing keeping it alive is that c1 points to
899 # it. c1 and c2 are in generation 0, and are in self-loops. There's
900 # a global weakref to c2 (c2wr), but that weakref has no callback.
901 # There are no other weakrefs.
902 #
903 # d0 has a __del__ method that references c2wr
904 # ^
905 # |
906 # | Generation 2 above dots
907 #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .
908 # | Generation 0 below dots
909 # |
910 # |
911 # ^->c1 ^->c2 has a wr but no callback
912 # | | | |
913 # <--v <--v
914 #
915 # So this is the nightmare: when generation 0 gets collected, we see
916 # that c2 has a callback-free weakref, and c1 doesn't even have a
917 # weakref. Collecting generation 0 doesn't see d0 at all. gc clears
918 # c1 and c2. Clearing c1 has the side effect of dropping the refcount
919 # on d0 to 0, so d0 goes away (despite that it's in an older
920 # generation) and d0's __del__ triggers. That in turn materializes
921 # a reference to c2 via c2wr(), but c2 gets cleared anyway by gc.
922
923 # We want to let gc happen "naturally", to preserve the distinction
924 # between generations.
925 detector = GC_Detector()
926 junk = []
927 i = 0
928 while not detector.gc_happened:
929 i += 1
930 if i > 10000:
931 self.fail("gc didn't happen after 10000 iterations")
932 self.assertEqual(len(ouch), 0)
933 junk.append([]) # this will eventually trigger gc
934
935 self.assertEqual(len(ouch), 1) # else __del__ wasn't invoked
936 for x in ouch:
937 # If __del__ resurrected c2, the instance would be damaged, with an
938 # empty __dict__.
939 self.assertEqual(x, None)
940
941def test_main():
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000942 enabled = gc.isenabled()
943 gc.disable()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000944 assert not gc.isenabled()
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000945 debug = gc.get_debug()
946 gc.set_debug(debug & ~gc.DEBUG_LEAK) # this test is supposed to leak
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000947
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000948 try:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000949 gc.collect() # Delete 2nd generation garbage
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000950 run_unittest(GCTests, GCTogglingTests, GCCallbackTests)
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000951 finally:
952 gc.set_debug(debug)
953 # test gc.enable() even if GC is disabled by default
954 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000955 print("restoring automatic collection")
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000956 # make sure to always test gc.enable()
957 gc.enable()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000958 assert gc.isenabled()
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000959 if not enabled:
960 gc.disable()
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000961
Guido van Rossumd8faa362007-04-27 19:54:29 +0000962if __name__ == "__main__":
963 test_main()