blob: e8f52a508f852a9c71531ee91e8364efd18d7f97 [file] [log] [blame]
Antoine Pitrou796564c2013-07-30 19:59:21 +02001import _testcapi
Guido van Rossumd8faa362007-04-27 19:54:29 +00002import unittest
Brett Cannon7a540732011-02-22 03:04:06 +00003from test.support import (verbose, refcount_test, run_unittest,
4 strip_python_stderr)
Antoine Pitrou5f454a02013-05-06 21:15:57 +02005from test.script_helper import assert_python_ok, make_script, temp_dir
6
Neil Schemenauer88c761a2001-07-12 13:25:53 +00007import sys
Antoine Pitrou2b0218a2012-09-06 00:59:49 +02008import time
Jeremy Hyltonc5007aa2000-06-30 05:02:53 +00009import gc
Tim Petersead8b7a2004-10-30 23:09:22 +000010import weakref
Jeremy Hyltonc5007aa2000-06-30 05:02:53 +000011
Antoine Pitrou2b0218a2012-09-06 00:59:49 +020012try:
13 import threading
14except ImportError:
15 threading = None
16
Guido van Rossumd8faa362007-04-27 19:54:29 +000017### Support code
18###############################################################################
Tim Peters0f81ab62003-04-08 16:39:48 +000019
Tim Petersead8b7a2004-10-30 23:09:22 +000020# Bug 1055820 has several tests of longstanding bugs involving weakrefs and
21# cyclic gc.
22
23# An instance of C1055820 has a self-loop, so becomes cyclic trash when
24# unreachable.
25class C1055820(object):
26 def __init__(self, i):
27 self.i = i
28 self.loop = self
29
30class GC_Detector(object):
31 # Create an instance I. Then gc hasn't happened again so long as
32 # I.gc_happened is false.
33
34 def __init__(self):
35 self.gc_happened = False
36
37 def it_happened(ignored):
38 self.gc_happened = True
39
40 # Create a piece of cyclic trash that triggers it_happened when
41 # gc collects it.
42 self.wr = weakref.ref(C1055820(666), it_happened)
43
Antoine Pitrou796564c2013-07-30 19:59:21 +020044@_testcapi.with_tp_del
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +000045class Uncollectable(object):
46 """Create a reference cycle with multiple __del__ methods.
47
48 An object in a reference cycle will never have zero references,
49 and so must be garbage collected. If one or more objects in the
50 cycle have __del__ methods, the gc refuses to guess an order,
51 and leaves the cycle uncollected."""
52 def __init__(self, partner=None):
53 if partner is None:
54 self.partner = Uncollectable(partner=self)
55 else:
56 self.partner = partner
Antoine Pitrou796564c2013-07-30 19:59:21 +020057 def __tp_del__(self):
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +000058 pass
Tim Petersead8b7a2004-10-30 23:09:22 +000059
Guido van Rossumd8faa362007-04-27 19:54:29 +000060### Tests
61###############################################################################
Tim Petersead8b7a2004-10-30 23:09:22 +000062
Guido van Rossumd8faa362007-04-27 19:54:29 +000063class GCTests(unittest.TestCase):
64 def test_list(self):
65 l = []
66 l.append(l)
67 gc.collect()
68 del l
69 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +000070
Guido van Rossumd8faa362007-04-27 19:54:29 +000071 def test_dict(self):
72 d = {}
73 d[1] = d
74 gc.collect()
75 del d
76 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +000077
Guido van Rossumd8faa362007-04-27 19:54:29 +000078 def test_tuple(self):
79 # since tuples are immutable we close the loop with a list
80 l = []
81 t = (l,)
82 l.append(t)
83 gc.collect()
84 del t
85 del l
86 self.assertEqual(gc.collect(), 2)
Tim Petersead8b7a2004-10-30 23:09:22 +000087
Guido van Rossumd8faa362007-04-27 19:54:29 +000088 def test_class(self):
89 class A:
90 pass
91 A.a = A
92 gc.collect()
93 del A
94 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +000095
Guido van Rossumd8faa362007-04-27 19:54:29 +000096 def test_newstyleclass(self):
97 class A(object):
98 pass
99 gc.collect()
100 del A
101 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000102
Guido van Rossumd8faa362007-04-27 19:54:29 +0000103 def test_instance(self):
104 class A:
105 pass
106 a = A()
107 a.a = a
108 gc.collect()
109 del a
110 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000111
Guido van Rossumd8faa362007-04-27 19:54:29 +0000112 def test_newinstance(self):
113 class A(object):
114 pass
115 a = A()
116 a.a = a
117 gc.collect()
118 del a
119 self.assertNotEqual(gc.collect(), 0)
120 class B(list):
121 pass
122 class C(B, A):
123 pass
124 a = C()
125 a.a = a
126 gc.collect()
127 del a
128 self.assertNotEqual(gc.collect(), 0)
129 del B, C
130 self.assertNotEqual(gc.collect(), 0)
131 A.a = A()
132 del A
133 self.assertNotEqual(gc.collect(), 0)
134 self.assertEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000135
Guido van Rossumd8faa362007-04-27 19:54:29 +0000136 def test_method(self):
137 # Tricky: self.__init__ is a bound method, it references the instance.
138 class A:
139 def __init__(self):
140 self.init = self.__init__
141 a = A()
142 gc.collect()
143 del a
144 self.assertNotEqual(gc.collect(), 0)
Tim Petersead8b7a2004-10-30 23:09:22 +0000145
Antoine Pitrou796564c2013-07-30 19:59:21 +0200146 def test_legacy_finalizer(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000147 # A() is uncollectable if it is part of a cycle, make sure it shows up
148 # in gc.garbage.
Antoine Pitrou796564c2013-07-30 19:59:21 +0200149 @_testcapi.with_tp_del
Guido van Rossumd8faa362007-04-27 19:54:29 +0000150 class A:
Antoine Pitrou796564c2013-07-30 19:59:21 +0200151 def __tp_del__(self): pass
Guido van Rossumd8faa362007-04-27 19:54:29 +0000152 class B:
153 pass
154 a = A()
155 a.a = a
156 id_a = id(a)
157 b = B()
158 b.b = b
159 gc.collect()
160 del a
161 del b
162 self.assertNotEqual(gc.collect(), 0)
163 for obj in gc.garbage:
164 if id(obj) == id_a:
165 del obj.a
166 break
167 else:
168 self.fail("didn't find obj in garbage (finalizer)")
169 gc.garbage.remove(obj)
Tim Petersead8b7a2004-10-30 23:09:22 +0000170
Antoine Pitrou796564c2013-07-30 19:59:21 +0200171 def test_legacy_finalizer_newclass(self):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000172 # A() is uncollectable if it is part of a cycle, make sure it shows up
173 # in gc.garbage.
Antoine Pitrou796564c2013-07-30 19:59:21 +0200174 @_testcapi.with_tp_del
Guido van Rossumd8faa362007-04-27 19:54:29 +0000175 class A(object):
Antoine Pitrou796564c2013-07-30 19:59:21 +0200176 def __tp_del__(self): pass
Guido van Rossumd8faa362007-04-27 19:54:29 +0000177 class B(object):
178 pass
179 a = A()
180 a.a = a
181 id_a = id(a)
182 b = B()
183 b.b = b
184 gc.collect()
185 del a
186 del b
187 self.assertNotEqual(gc.collect(), 0)
188 for obj in gc.garbage:
189 if id(obj) == id_a:
190 del obj.a
191 break
192 else:
193 self.fail("didn't find obj in garbage (finalizer)")
194 gc.garbage.remove(obj)
Tim Petersead8b7a2004-10-30 23:09:22 +0000195
Guido van Rossumd8faa362007-04-27 19:54:29 +0000196 def test_function(self):
197 # Tricky: f -> d -> f, code should call d.clear() after the exec to
198 # break the cycle.
199 d = {}
200 exec("def f(): pass\n", d)
201 gc.collect()
202 del d
203 self.assertEqual(gc.collect(), 2)
Tim Petersead8b7a2004-10-30 23:09:22 +0000204
Brett Cannon7a540732011-02-22 03:04:06 +0000205 @refcount_test
Guido van Rossumd8faa362007-04-27 19:54:29 +0000206 def test_frame(self):
207 def f():
208 frame = sys._getframe()
209 gc.collect()
210 f()
211 self.assertEqual(gc.collect(), 1)
Tim Petersead8b7a2004-10-30 23:09:22 +0000212
Guido van Rossumd8faa362007-04-27 19:54:29 +0000213 def test_saveall(self):
214 # Verify that cyclic garbage like lists show up in gc.garbage if the
215 # SAVEALL option is enabled.
Tim Petersead8b7a2004-10-30 23:09:22 +0000216
Guido van Rossumd8faa362007-04-27 19:54:29 +0000217 # First make sure we don't save away other stuff that just happens to
218 # be waiting for collection.
219 gc.collect()
220 # if this fails, someone else created immortal trash
221 self.assertEqual(gc.garbage, [])
222
223 L = []
224 L.append(L)
225 id_L = id(L)
226
227 debug = gc.get_debug()
228 gc.set_debug(debug | gc.DEBUG_SAVEALL)
229 del L
230 gc.collect()
231 gc.set_debug(debug)
232
233 self.assertEqual(len(gc.garbage), 1)
234 obj = gc.garbage.pop()
235 self.assertEqual(id(obj), id_L)
236
237 def test_del(self):
238 # __del__ methods can trigger collection, make this to happen
239 thresholds = gc.get_threshold()
240 gc.enable()
241 gc.set_threshold(1)
242
243 class A:
244 def __del__(self):
245 dir(self)
246 a = A()
247 del a
248
249 gc.disable()
250 gc.set_threshold(*thresholds)
251
252 def test_del_newclass(self):
253 # __del__ methods can trigger collection, make this to happen
254 thresholds = gc.get_threshold()
255 gc.enable()
256 gc.set_threshold(1)
257
258 class A(object):
259 def __del__(self):
260 dir(self)
261 a = A()
262 del a
263
264 gc.disable()
265 gc.set_threshold(*thresholds)
266
Christian Heimesa156e092008-02-16 07:38:31 +0000267 # The following two tests are fragile:
268 # They precisely count the number of allocations,
269 # which is highly implementation-dependent.
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200270 # For example, disposed tuples are not freed, but reused.
271 # To minimize variations, though, we first store the get_count() results
272 # and check them at the end.
Brett Cannon7a540732011-02-22 03:04:06 +0000273 @refcount_test
Guido van Rossumd8faa362007-04-27 19:54:29 +0000274 def test_get_count(self):
275 gc.collect()
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200276 a, b, c = gc.get_count()
277 x = []
278 d, e, f = gc.get_count()
279 self.assertEqual((b, c), (0, 0))
280 self.assertEqual((e, f), (0, 0))
281 # This is less fragile than asserting that a equals 0.
282 self.assertLess(a, 5)
283 # Between the two calls to get_count(), at least one object was
284 # created (the list).
285 self.assertGreater(d, a)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000286
Brett Cannon7a540732011-02-22 03:04:06 +0000287 @refcount_test
Guido van Rossumd8faa362007-04-27 19:54:29 +0000288 def test_collect_generations(self):
289 gc.collect()
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200290 # This object will "trickle" into generation N + 1 after
291 # each call to collect(N)
292 x = []
Guido van Rossumd8faa362007-04-27 19:54:29 +0000293 gc.collect(0)
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200294 # x is now in gen 1
295 a, b, c = gc.get_count()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000296 gc.collect(1)
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200297 # x is now in gen 2
298 d, e, f = gc.get_count()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000299 gc.collect(2)
Antoine Pitroub35f29a2011-04-04 19:50:42 +0200300 # x is now in gen 3
301 g, h, i = gc.get_count()
302 # We don't check a, d, g since their exact values depends on
303 # internal implementation details of the interpreter.
304 self.assertEqual((b, c), (1, 0))
305 self.assertEqual((e, f), (0, 1))
306 self.assertEqual((h, i), (0, 0))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000307
308 def test_trashcan(self):
309 class Ouch:
310 n = 0
311 def __del__(self):
312 Ouch.n = Ouch.n + 1
313 if Ouch.n % 17 == 0:
314 gc.collect()
315
316 # "trashcan" is a hack to prevent stack overflow when deallocating
317 # very deeply nested tuples etc. It works in part by abusing the
318 # type pointer and refcount fields, and that can yield horrible
319 # problems when gc tries to traverse the structures.
320 # If this test fails (as it does in 2.0, 2.1 and 2.2), it will
321 # most likely die via segfault.
322
323 # Note: In 2.3 the possibility for compiling without cyclic gc was
324 # removed, and that in turn allows the trashcan mechanism to work
325 # via much simpler means (e.g., it never abuses the type pointer or
326 # refcount fields anymore). Since it's much less likely to cause a
327 # problem now, the various constants in this expensive (we force a lot
328 # of full collections) test are cut back from the 2.2 version.
329 gc.enable()
330 N = 150
331 for count in range(2):
332 t = []
333 for i in range(N):
334 t = [t, Ouch()]
335 u = []
336 for i in range(N):
337 u = [u, Ouch()]
338 v = {}
339 for i in range(N):
340 v = {1: v, 2: Ouch()}
341 gc.disable()
342
Antoine Pitrou2b0218a2012-09-06 00:59:49 +0200343 @unittest.skipUnless(threading, "test meaningless on builds without threads")
344 def test_trashcan_threads(self):
345 # Issue #13992: trashcan mechanism should be thread-safe
346 NESTING = 60
347 N_THREADS = 2
348
349 def sleeper_gen():
350 """A generator that releases the GIL when closed or dealloc'ed."""
351 try:
352 yield
353 finally:
354 time.sleep(0.000001)
355
356 class C(list):
357 # Appending to a list is atomic, which avoids the use of a lock.
358 inits = []
359 dels = []
360 def __init__(self, alist):
361 self[:] = alist
362 C.inits.append(None)
363 def __del__(self):
364 # This __del__ is called by subtype_dealloc().
365 C.dels.append(None)
366 # `g` will release the GIL when garbage-collected. This
367 # helps assert subtype_dealloc's behaviour when threads
368 # switch in the middle of it.
369 g = sleeper_gen()
370 next(g)
371 # Now that __del__ is finished, subtype_dealloc will proceed
372 # to call list_dealloc, which also uses the trashcan mechanism.
373
374 def make_nested():
375 """Create a sufficiently nested container object so that the
376 trashcan mechanism is invoked when deallocating it."""
377 x = C([])
378 for i in range(NESTING):
379 x = [C([x])]
380 del x
381
382 def run_thread():
383 """Exercise make_nested() in a loop."""
384 while not exit:
385 make_nested()
386
387 old_switchinterval = sys.getswitchinterval()
388 sys.setswitchinterval(1e-5)
389 try:
390 exit = False
391 threads = []
392 for i in range(N_THREADS):
393 t = threading.Thread(target=run_thread)
394 threads.append(t)
395 for t in threads:
396 t.start()
397 time.sleep(1.0)
398 exit = True
399 for t in threads:
400 t.join()
401 finally:
402 sys.setswitchinterval(old_switchinterval)
403 gc.collect()
404 self.assertEqual(len(C.inits), len(C.dels))
405
Guido van Rossumd8faa362007-04-27 19:54:29 +0000406 def test_boom(self):
407 class Boom:
408 def __getattr__(self, someattribute):
409 del self.attr
410 raise AttributeError
411
412 a = Boom()
413 b = Boom()
414 a.attr = b
415 b.attr = a
416
417 gc.collect()
418 garbagelen = len(gc.garbage)
419 del a, b
420 # a<->b are in a trash cycle now. Collection will invoke
421 # Boom.__getattr__ (to see whether a and b have __del__ methods), and
422 # __getattr__ deletes the internal "attr" attributes as a side effect.
423 # That causes the trash cycle to get reclaimed via refcounts falling to
424 # 0, thus mutating the trash graph as a side effect of merely asking
425 # whether __del__ exists. This used to (before 2.3b1) crash Python.
426 # Now __getattr__ isn't called.
427 self.assertEqual(gc.collect(), 4)
428 self.assertEqual(len(gc.garbage), garbagelen)
429
430 def test_boom2(self):
431 class Boom2:
432 def __init__(self):
433 self.x = 0
434
435 def __getattr__(self, someattribute):
436 self.x += 1
437 if self.x > 1:
438 del self.attr
439 raise AttributeError
440
441 a = Boom2()
442 b = Boom2()
443 a.attr = b
444 b.attr = a
445
446 gc.collect()
447 garbagelen = len(gc.garbage)
448 del a, b
449 # Much like test_boom(), except that __getattr__ doesn't break the
450 # cycle until the second time gc checks for __del__. As of 2.3b1,
451 # there isn't a second time, so this simply cleans up the trash cycle.
452 # We expect a, b, a.__dict__ and b.__dict__ (4 objects) to get
453 # reclaimed this way.
454 self.assertEqual(gc.collect(), 4)
455 self.assertEqual(len(gc.garbage), garbagelen)
456
457 def test_boom_new(self):
458 # boom__new and boom2_new are exactly like boom and boom2, except use
459 # new-style classes.
460
461 class Boom_New(object):
462 def __getattr__(self, someattribute):
463 del self.attr
464 raise AttributeError
465
466 a = Boom_New()
467 b = Boom_New()
468 a.attr = b
469 b.attr = a
470
471 gc.collect()
472 garbagelen = len(gc.garbage)
473 del a, b
474 self.assertEqual(gc.collect(), 4)
475 self.assertEqual(len(gc.garbage), garbagelen)
476
477 def test_boom2_new(self):
478 class Boom2_New(object):
479 def __init__(self):
480 self.x = 0
481
482 def __getattr__(self, someattribute):
483 self.x += 1
484 if self.x > 1:
485 del self.attr
486 raise AttributeError
487
488 a = Boom2_New()
489 b = Boom2_New()
490 a.attr = b
491 b.attr = a
492
493 gc.collect()
494 garbagelen = len(gc.garbage)
495 del a, b
496 self.assertEqual(gc.collect(), 4)
497 self.assertEqual(len(gc.garbage), garbagelen)
498
499 def test_get_referents(self):
500 alist = [1, 3, 5]
501 got = gc.get_referents(alist)
502 got.sort()
503 self.assertEqual(got, alist)
504
505 atuple = tuple(alist)
506 got = gc.get_referents(atuple)
507 got.sort()
508 self.assertEqual(got, alist)
509
510 adict = {1: 3, 5: 7}
511 expected = [1, 3, 5, 7]
512 got = gc.get_referents(adict)
513 got.sort()
514 self.assertEqual(got, expected)
515
516 got = gc.get_referents([1, 2], {3: 4}, (0, 0, 0))
517 got.sort()
Guido van Rossum805365e2007-05-07 22:24:25 +0000518 self.assertEqual(got, [0, 0] + list(range(5)))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000519
520 self.assertEqual(gc.get_referents(1, 'a', 4j), [])
521
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000522 def test_is_tracked(self):
523 # Atomic built-in types are not tracked, user-defined objects and
524 # mutable containers are.
525 # NOTE: types with special optimizations (e.g. tuple) have tests
526 # in their own test files instead.
527 self.assertFalse(gc.is_tracked(None))
528 self.assertFalse(gc.is_tracked(1))
529 self.assertFalse(gc.is_tracked(1.0))
530 self.assertFalse(gc.is_tracked(1.0 + 5.0j))
531 self.assertFalse(gc.is_tracked(True))
532 self.assertFalse(gc.is_tracked(False))
533 self.assertFalse(gc.is_tracked(b"a"))
534 self.assertFalse(gc.is_tracked("a"))
535 self.assertFalse(gc.is_tracked(bytearray(b"a")))
536 self.assertFalse(gc.is_tracked(type))
537 self.assertFalse(gc.is_tracked(int))
538 self.assertFalse(gc.is_tracked(object))
539 self.assertFalse(gc.is_tracked(object()))
540
541 class UserClass:
542 pass
543 self.assertTrue(gc.is_tracked(gc))
544 self.assertTrue(gc.is_tracked(UserClass))
545 self.assertTrue(gc.is_tracked(UserClass()))
546 self.assertTrue(gc.is_tracked([]))
547 self.assertTrue(gc.is_tracked(set()))
548
Guido van Rossumd8faa362007-04-27 19:54:29 +0000549 def test_bug1055820b(self):
550 # Corresponds to temp2b.py in the bug report.
551
552 ouch = []
553 def callback(ignored):
554 ouch[:] = [wr() for wr in WRs]
555
556 Cs = [C1055820(i) for i in range(2)]
557 WRs = [weakref.ref(c, callback) for c in Cs]
558 c = None
559
560 gc.collect()
561 self.assertEqual(len(ouch), 0)
562 # Make the two instances trash, and collect again. The bug was that
563 # the callback materialized a strong reference to an instance, but gc
564 # cleared the instance's dict anyway.
565 Cs = None
566 gc.collect()
567 self.assertEqual(len(ouch), 2) # else the callbacks didn't run
568 for x in ouch:
569 # If the callback resurrected one of these guys, the instance
570 # would be damaged, with an empty __dict__.
571 self.assertEqual(x, None)
572
Antoine Pitrou696e0352010-08-08 22:18:46 +0000573 def test_garbage_at_shutdown(self):
574 import subprocess
575 code = """if 1:
576 import gc
Antoine Pitrou796564c2013-07-30 19:59:21 +0200577 import _testcapi
578 @_testcapi.with_tp_del
Antoine Pitrou696e0352010-08-08 22:18:46 +0000579 class X:
580 def __init__(self, name):
581 self.name = name
582 def __repr__(self):
583 return "<X %%r>" %% self.name
Antoine Pitrou796564c2013-07-30 19:59:21 +0200584 def __tp_del__(self):
Antoine Pitrou696e0352010-08-08 22:18:46 +0000585 pass
586
587 x = X('first')
588 x.x = x
589 x.y = X('second')
590 del x
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000591 gc.set_debug(%s)
Antoine Pitrou696e0352010-08-08 22:18:46 +0000592 """
593 def run_command(code):
Georg Brandl08be72d2010-10-24 15:11:22 +0000594 p = subprocess.Popen([sys.executable, "-Wd", "-c", code],
Antoine Pitrou696e0352010-08-08 22:18:46 +0000595 stdout=subprocess.PIPE,
596 stderr=subprocess.PIPE)
597 stdout, stderr = p.communicate()
Brian Curtin8291af22010-11-01 16:40:17 +0000598 p.stdout.close()
599 p.stderr.close()
Antoine Pitrou696e0352010-08-08 22:18:46 +0000600 self.assertEqual(p.returncode, 0)
601 self.assertEqual(stdout.strip(), b"")
602 return strip_python_stderr(stderr)
603
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000604 stderr = run_command(code % "0")
Georg Brandl08be72d2010-10-24 15:11:22 +0000605 self.assertIn(b"ResourceWarning: gc: 2 uncollectable objects at "
606 b"shutdown; use", stderr)
Antoine Pitrouaee47562010-09-16 15:04:49 +0000607 self.assertNotIn(b"<X 'first'>", stderr)
Antoine Pitrou696e0352010-08-08 22:18:46 +0000608 # With DEBUG_UNCOLLECTABLE, the garbage list gets printed
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000609 stderr = run_command(code % "gc.DEBUG_UNCOLLECTABLE")
Georg Brandl08be72d2010-10-24 15:11:22 +0000610 self.assertIn(b"ResourceWarning: gc: 2 uncollectable objects at "
611 b"shutdown", stderr)
Antoine Pitrouaee47562010-09-16 15:04:49 +0000612 self.assertTrue(
613 (b"[<X 'first'>, <X 'second'>]" in stderr) or
614 (b"[<X 'second'>, <X 'first'>]" in stderr), stderr)
Antoine Pitrou2ed94eb2010-09-14 09:48:39 +0000615 # With DEBUG_SAVEALL, no additional message should get printed
616 # (because gc.garbage also contains normally reclaimable cyclic
617 # references, and its elements get printed at runtime anyway).
618 stderr = run_command(code % "gc.DEBUG_SAVEALL")
619 self.assertNotIn(b"uncollectable objects at shutdown", stderr)
620
Antoine Pitrou5f454a02013-05-06 21:15:57 +0200621 def test_gc_main_module_at_shutdown(self):
622 # Create a reference cycle through the __main__ module and check
623 # it gets collected at interpreter shutdown.
624 code = """if 1:
625 import weakref
626 class C:
627 def __del__(self):
628 print('__del__ called')
629 l = [C()]
630 l.append(l)
631 """
632 rc, out, err = assert_python_ok('-c', code)
633 self.assertEqual(out.strip(), b'__del__ called')
634
635 def test_gc_ordinary_module_at_shutdown(self):
636 # Same as above, but with a non-__main__ module.
637 with temp_dir() as script_dir:
638 module = """if 1:
639 import weakref
640 class C:
641 def __del__(self):
642 print('__del__ called')
643 l = [C()]
644 l.append(l)
645 """
646 code = """if 1:
647 import sys
648 sys.path.insert(0, %r)
649 import gctest
650 """ % (script_dir,)
651 make_script(script_dir, 'gctest', module)
652 rc, out, err = assert_python_ok('-c', code)
653 self.assertEqual(out.strip(), b'__del__ called')
654
Antoine Pitroud4156c12012-10-30 22:43:19 +0100655 def test_get_stats(self):
656 stats = gc.get_stats()
657 self.assertEqual(len(stats), 3)
658 for st in stats:
659 self.assertIsInstance(st, dict)
660 self.assertEqual(set(st),
661 {"collected", "collections", "uncollectable"})
662 self.assertGreaterEqual(st["collected"], 0)
663 self.assertGreaterEqual(st["collections"], 0)
664 self.assertGreaterEqual(st["uncollectable"], 0)
665 # Check that collection counts are incremented correctly
666 if gc.isenabled():
667 self.addCleanup(gc.enable)
668 gc.disable()
669 old = gc.get_stats()
670 gc.collect(0)
671 new = gc.get_stats()
672 self.assertEqual(new[0]["collections"], old[0]["collections"] + 1)
673 self.assertEqual(new[1]["collections"], old[1]["collections"])
674 self.assertEqual(new[2]["collections"], old[2]["collections"])
675 gc.collect(2)
676 new = gc.get_stats()
677 self.assertEqual(new[0]["collections"], old[0]["collections"] + 1)
678 self.assertEqual(new[1]["collections"], old[1]["collections"])
679 self.assertEqual(new[2]["collections"], old[2]["collections"] + 1)
680
Antoine Pitrou696e0352010-08-08 22:18:46 +0000681
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000682class GCCallbackTests(unittest.TestCase):
683 def setUp(self):
684 # Save gc state and disable it.
685 self.enabled = gc.isenabled()
686 gc.disable()
687 self.debug = gc.get_debug()
688 gc.set_debug(0)
689 gc.callbacks.append(self.cb1)
690 gc.callbacks.append(self.cb2)
Antoine Pitrou6b64fc62012-04-16 21:29:02 +0200691 self.othergarbage = []
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000692
693 def tearDown(self):
694 # Restore gc state
695 del self.visit
696 gc.callbacks.remove(self.cb1)
697 gc.callbacks.remove(self.cb2)
698 gc.set_debug(self.debug)
699 if self.enabled:
700 gc.enable()
701 # destroy any uncollectables
702 gc.collect()
703 for obj in gc.garbage:
704 if isinstance(obj, Uncollectable):
705 obj.partner = None
706 del gc.garbage[:]
Antoine Pitrou6b64fc62012-04-16 21:29:02 +0200707 del self.othergarbage
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000708 gc.collect()
709
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000710 def preclean(self):
711 # Remove all fluff from the system. Invoke this function
712 # manually rather than through self.setUp() for maximum
713 # safety.
714 self.visit = []
715 gc.collect()
716 garbage, gc.garbage[:] = gc.garbage[:], []
717 self.othergarbage.append(garbage)
718 self.visit = []
719
720 def cb1(self, phase, info):
721 self.visit.append((1, phase, dict(info)))
722
723 def cb2(self, phase, info):
724 self.visit.append((2, phase, dict(info)))
725 if phase == "stop" and hasattr(self, "cleanup"):
726 # Clean Uncollectable from garbage
727 uc = [e for e in gc.garbage if isinstance(e, Uncollectable)]
728 gc.garbage[:] = [e for e in gc.garbage
729 if not isinstance(e, Uncollectable)]
730 for e in uc:
731 e.partner = None
732
Antoine Pitroude3c73b2012-04-16 21:29:58 +0200733 def test_collect(self):
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000734 self.preclean()
735 gc.collect()
736 # Algorithmically verify the contents of self.visit
737 # because it is long and tortuous.
738
739 # Count the number of visits to each callback
740 n = [v[0] for v in self.visit]
741 n1 = [i for i in n if i == 1]
742 n2 = [i for i in n if i == 2]
743 self.assertEqual(n1, [1]*2)
744 self.assertEqual(n2, [2]*2)
745
746 # Count that we got the right number of start and stop callbacks.
747 n = [v[1] for v in self.visit]
748 n1 = [i for i in n if i == "start"]
749 n2 = [i for i in n if i == "stop"]
750 self.assertEqual(n1, ["start"]*2)
751 self.assertEqual(n2, ["stop"]*2)
752
753 # Check that we got the right info dict for all callbacks
754 for v in self.visit:
755 info = v[2]
756 self.assertTrue("generation" in info)
757 self.assertTrue("collected" in info)
758 self.assertTrue("uncollectable" in info)
759
Antoine Pitroude3c73b2012-04-16 21:29:58 +0200760 def test_collect_generation(self):
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000761 self.preclean()
762 gc.collect(2)
763 for v in self.visit:
764 info = v[2]
765 self.assertEqual(info["generation"], 2)
766
Antoine Pitroude3c73b2012-04-16 21:29:58 +0200767 def test_collect_garbage(self):
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000768 self.preclean()
769 # Each of these cause four objects to be garbage: Two
770 # Uncolectables and their instance dicts.
771 Uncollectable()
772 Uncollectable()
773 C1055820(666)
774 gc.collect()
775 for v in self.visit:
776 if v[1] != "stop":
777 continue
778 info = v[2]
779 self.assertEqual(info["collected"], 2)
780 self.assertEqual(info["uncollectable"], 8)
781
782 # We should now have the Uncollectables in gc.garbage
783 self.assertEqual(len(gc.garbage), 4)
784 for e in gc.garbage:
785 self.assertIsInstance(e, Uncollectable)
786
787 # Now, let our callback handle the Uncollectable instances
788 self.cleanup=True
789 self.visit = []
790 gc.garbage[:] = []
791 gc.collect()
792 for v in self.visit:
793 if v[1] != "stop":
794 continue
795 info = v[2]
796 self.assertEqual(info["collected"], 0)
797 self.assertEqual(info["uncollectable"], 4)
798
799 # Uncollectables should be gone
800 self.assertEqual(len(gc.garbage), 0)
801
802
Guido van Rossumd8faa362007-04-27 19:54:29 +0000803class GCTogglingTests(unittest.TestCase):
804 def setUp(self):
805 gc.enable()
806
807 def tearDown(self):
808 gc.disable()
809
810 def test_bug1055820c(self):
811 # Corresponds to temp2c.py in the bug report. This is pretty
812 # elaborate.
813
814 c0 = C1055820(0)
815 # Move c0 into generation 2.
816 gc.collect()
817
818 c1 = C1055820(1)
819 c1.keep_c0_alive = c0
820 del c0.loop # now only c1 keeps c0 alive
821
822 c2 = C1055820(2)
823 c2wr = weakref.ref(c2) # no callback!
824
825 ouch = []
826 def callback(ignored):
Tim Petersead8b7a2004-10-30 23:09:22 +0000827 ouch[:] = [c2wr()]
828
Guido van Rossumd8faa362007-04-27 19:54:29 +0000829 # The callback gets associated with a wr on an object in generation 2.
830 c0wr = weakref.ref(c0, callback)
Tim Petersead8b7a2004-10-30 23:09:22 +0000831
Guido van Rossumd8faa362007-04-27 19:54:29 +0000832 c0 = c1 = c2 = None
Tim Petersead8b7a2004-10-30 23:09:22 +0000833
Guido van Rossumd8faa362007-04-27 19:54:29 +0000834 # What we've set up: c0, c1, and c2 are all trash now. c0 is in
835 # generation 2. The only thing keeping it alive is that c1 points to
836 # it. c1 and c2 are in generation 0, and are in self-loops. There's a
837 # global weakref to c2 (c2wr), but that weakref has no callback.
838 # There's also a global weakref to c0 (c0wr), and that does have a
839 # callback, and that callback references c2 via c2wr().
840 #
841 # c0 has a wr with callback, which 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 c0 at all, and c0 is
856 # the only object that has a weakref with a callback. gc clears c1
857 # and c2. Clearing c1 has the side effect of dropping the refcount on
858 # c0 to 0, so c0 goes away (despite that it's in an older generation)
859 # and c0's wr callback triggers. That in turn materializes a reference
860 # to c2 via c2wr(), but c2 gets cleared anyway by gc.
Tim Petersead8b7a2004-10-30 23:09:22 +0000861
Guido van Rossumd8faa362007-04-27 19:54:29 +0000862 # We want to let gc happen "naturally", to preserve the distinction
863 # between generations.
864 junk = []
865 i = 0
866 detector = GC_Detector()
867 while not detector.gc_happened:
868 i += 1
869 if i > 10000:
870 self.fail("gc didn't happen after 10000 iterations")
871 self.assertEqual(len(ouch), 0)
872 junk.append([]) # this will eventually trigger gc
Tim Petersead8b7a2004-10-30 23:09:22 +0000873
Guido van Rossumd8faa362007-04-27 19:54:29 +0000874 self.assertEqual(len(ouch), 1) # else the callback wasn't invoked
875 for x in ouch:
876 # If the callback resurrected c2, the instance would be damaged,
877 # with an empty __dict__.
878 self.assertEqual(x, None)
Tim Petersead8b7a2004-10-30 23:09:22 +0000879
Guido van Rossumd8faa362007-04-27 19:54:29 +0000880 def test_bug1055820d(self):
881 # Corresponds to temp2d.py in the bug report. This is very much like
882 # test_bug1055820c, but uses a __del__ method instead of a weakref
883 # callback to sneak in a resurrection of cyclic trash.
Tim Petersead8b7a2004-10-30 23:09:22 +0000884
Guido van Rossumd8faa362007-04-27 19:54:29 +0000885 ouch = []
886 class D(C1055820):
887 def __del__(self):
888 ouch[:] = [c2wr()]
Tim Petersead8b7a2004-10-30 23:09:22 +0000889
Guido van Rossumd8faa362007-04-27 19:54:29 +0000890 d0 = D(0)
891 # Move all the above into generation 2.
892 gc.collect()
Tim Petersead8b7a2004-10-30 23:09:22 +0000893
Guido van Rossumd8faa362007-04-27 19:54:29 +0000894 c1 = C1055820(1)
895 c1.keep_d0_alive = d0
896 del d0.loop # now only c1 keeps d0 alive
Tim Petersead8b7a2004-10-30 23:09:22 +0000897
Guido van Rossumd8faa362007-04-27 19:54:29 +0000898 c2 = C1055820(2)
899 c2wr = weakref.ref(c2) # no callback!
Tim Petersead8b7a2004-10-30 23:09:22 +0000900
Guido van Rossumd8faa362007-04-27 19:54:29 +0000901 d0 = c1 = c2 = None
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000902
Guido van Rossumd8faa362007-04-27 19:54:29 +0000903 # What we've set up: d0, c1, and c2 are all trash now. d0 is in
904 # generation 2. The only thing keeping it alive is that c1 points to
905 # it. c1 and c2 are in generation 0, and are in self-loops. There's
906 # a global weakref to c2 (c2wr), but that weakref has no callback.
907 # There are no other weakrefs.
908 #
909 # d0 has a __del__ method that references c2wr
910 # ^
911 # |
912 # | Generation 2 above dots
913 #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .
914 # | Generation 0 below dots
915 # |
916 # |
917 # ^->c1 ^->c2 has a wr but no callback
918 # | | | |
919 # <--v <--v
920 #
921 # So this is the nightmare: when generation 0 gets collected, we see
922 # that c2 has a callback-free weakref, and c1 doesn't even have a
923 # weakref. Collecting generation 0 doesn't see d0 at all. gc clears
924 # c1 and c2. Clearing c1 has the side effect of dropping the refcount
925 # on d0 to 0, so d0 goes away (despite that it's in an older
926 # generation) and d0's __del__ triggers. That in turn materializes
927 # a reference to c2 via c2wr(), but c2 gets cleared anyway by gc.
928
929 # We want to let gc happen "naturally", to preserve the distinction
930 # between generations.
931 detector = GC_Detector()
932 junk = []
933 i = 0
934 while not detector.gc_happened:
935 i += 1
936 if i > 10000:
937 self.fail("gc didn't happen after 10000 iterations")
938 self.assertEqual(len(ouch), 0)
939 junk.append([]) # this will eventually trigger gc
940
941 self.assertEqual(len(ouch), 1) # else __del__ wasn't invoked
942 for x in ouch:
943 # If __del__ resurrected c2, the instance would be damaged, with an
944 # empty __dict__.
945 self.assertEqual(x, None)
946
947def test_main():
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000948 enabled = gc.isenabled()
949 gc.disable()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000950 assert not gc.isenabled()
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000951 debug = gc.get_debug()
952 gc.set_debug(debug & ~gc.DEBUG_LEAK) # this test is supposed to leak
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000953
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000954 try:
Guido van Rossumd8faa362007-04-27 19:54:29 +0000955 gc.collect() # Delete 2nd generation garbage
Kristján Valur Jónsson69c63522012-04-15 11:41:32 +0000956 run_unittest(GCTests, GCTogglingTests, GCCallbackTests)
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000957 finally:
958 gc.set_debug(debug)
959 # test gc.enable() even if GC is disabled by default
960 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000961 print("restoring automatic collection")
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000962 # make sure to always test gc.enable()
963 gc.enable()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000964 assert gc.isenabled()
Neil Schemenauerfaae2662000-09-22 15:26:20 +0000965 if not enabled:
966 gc.disable()
Vladimir Marangozovf9d20c32000-08-06 22:45:31 +0000967
Guido van Rossumd8faa362007-04-27 19:54:29 +0000968if __name__ == "__main__":
969 test_main()