/Lib/test/test_gc.py
Python | 617 lines | 390 code | 85 blank | 142 comment | 42 complexity | 3b4cc69c294c0f93c1628f7c88e4e953 MD5 | raw file
1import unittest 2from test.test_support import verbose, run_unittest 3import sys 4import gc 5import weakref 6try: 7 import _llvm 8except ImportError: 9 _llvm = None 10 11### Support code 12############################################################################### 13 14# Bug 1055820 has several tests of longstanding bugs involving weakrefs and 15# cyclic gc. 16 17# An instance of C1055820 has a self-loop, so becomes cyclic trash when 18# unreachable. 19class C1055820(object): 20 def __init__(self, i): 21 self.i = i 22 self.loop = self 23 24class GC_Detector(object): 25 # Create an instance I. Then gc hasn't happened again so long as 26 # I.gc_happened is false. 27 28 def __init__(self): 29 self.gc_happened = False 30 31 def it_happened(ignored): 32 self.gc_happened = True 33 34 # Create a piece of cyclic trash that triggers it_happened when 35 # gc collects it. 36 self.wr = weakref.ref(C1055820(666), it_happened) 37 38 39### Tests 40############################################################################### 41 42class GCTests(unittest.TestCase): 43 def test_list(self): 44 l = [] 45 l.append(l) 46 gc.collect() 47 del l 48 self.assertEqual(gc.collect(), 1) 49 50 def test_dict(self): 51 d = {} 52 d[1] = d 53 gc.collect() 54 del d 55 self.assertEqual(gc.collect(), 1) 56 57 def test_tuple(self): 58 # since tuples are immutable we close the loop with a list 59 l = [] 60 t = (l,) 61 l.append(t) 62 gc.collect() 63 del t 64 del l 65 self.assertEqual(gc.collect(), 2) 66 67 def test_class(self): 68 class A: 69 pass 70 A.a = A 71 gc.collect() 72 del A 73 self.assertNotEqual(gc.collect(), 0) 74 75 def test_newstyleclass(self): 76 class A(object): 77 pass 78 gc.collect() 79 del A 80 self.assertNotEqual(gc.collect(), 0) 81 82 def test_instance(self): 83 class A: 84 pass 85 a = A() 86 a.a = a 87 gc.collect() 88 del a 89 self.assertNotEqual(gc.collect(), 0) 90 91 def test_newinstance(self): 92 class A(object): 93 pass 94 a = A() 95 a.a = a 96 gc.collect() 97 del a 98 self.assertNotEqual(gc.collect(), 0) 99 class B(list): 100 pass 101 class C(B, A): 102 pass 103 a = C() 104 a.a = a 105 gc.collect() 106 del a 107 self.assertNotEqual(gc.collect(), 0) 108 del B, C 109 # If we don't clear the feedback array, the FDO system will hold 110 # references to B and C, which prevent gc.collect() from collecting 111 # them. 112 if _llvm: 113 _llvm.clear_feedback(self.test_newinstance) 114 self.assertNotEqual(gc.collect(), 0) 115 A.a = A() 116 del A 117 self.assertNotEqual(gc.collect(), 0) 118 self.assertEqual(gc.collect(), 0) 119 120 def test_method(self): 121 # Tricky: self.__init__ is a bound method, it references the instance. 122 class A: 123 def __init__(self): 124 self.init = self.__init__ 125 a = A() 126 gc.collect() 127 del a 128 self.assertNotEqual(gc.collect(), 0) 129 130 def test_finalizer(self): 131 # A() is uncollectable if it is part of a cycle, make sure it shows up 132 # in gc.garbage. 133 class A: 134 def __del__(self): pass 135 class B: 136 pass 137 a = A() 138 a.a = a 139 id_a = id(a) 140 b = B() 141 b.b = b 142 gc.collect() 143 del a 144 del b 145 self.assertNotEqual(gc.collect(), 0) 146 for obj in gc.garbage: 147 if id(obj) == id_a: 148 del obj.a 149 break 150 else: 151 self.fail("didn't find obj in garbage (finalizer)") 152 gc.garbage.remove(obj) 153 154 def test_finalizer_newclass(self): 155 # A() is uncollectable if it is part of a cycle, make sure it shows up 156 # in gc.garbage. 157 class A(object): 158 def __del__(self): pass 159 class B(object): 160 pass 161 a = A() 162 a.a = a 163 id_a = id(a) 164 b = B() 165 b.b = b 166 gc.collect() 167 del a 168 del b 169 self.assertNotEqual(gc.collect(), 0) 170 for obj in gc.garbage: 171 if id(obj) == id_a: 172 del obj.a 173 break 174 else: 175 self.fail("didn't find obj in garbage (finalizer)") 176 gc.garbage.remove(obj) 177 178 def test_function(self): 179 # Tricky: f -> d -> f, code should call d.clear() after the exec to 180 # break the cycle. 181 d = {} 182 exec("def f(): pass\n") in d 183 gc.collect() 184 del d 185 self.assertEqual(gc.collect(), 2) 186 187 def test_frame(self): 188 def f(): 189 frame = sys._getframe() 190 gc.collect() 191 f() 192 self.assertEqual(gc.collect(), 1) 193 194 def test_saveall(self): 195 # Verify that cyclic garbage like lists show up in gc.garbage if the 196 # SAVEALL option is enabled. 197 198 # First make sure we don't save away other stuff that just happens to 199 # be waiting for collection. 200 gc.collect() 201 # if this fails, someone else created immortal trash 202 self.assertEqual(gc.garbage, []) 203 204 L = [] 205 L.append(L) 206 id_L = id(L) 207 208 debug = gc.get_debug() 209 gc.set_debug(debug | gc.DEBUG_SAVEALL) 210 del L 211 gc.collect() 212 gc.set_debug(debug) 213 214 self.assertEqual(len(gc.garbage), 1) 215 obj = gc.garbage.pop() 216 self.assertEqual(id(obj), id_L) 217 218 def test_del(self): 219 # __del__ methods can trigger collection, make this to happen 220 thresholds = gc.get_threshold() 221 gc.enable() 222 gc.set_threshold(1) 223 224 class A: 225 def __del__(self): 226 dir(self) 227 a = A() 228 del a 229 230 gc.disable() 231 gc.set_threshold(*thresholds) 232 233 def test_del_newclass(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(object): 240 def __del__(self): 241 dir(self) 242 a = A() 243 del a 244 245 gc.disable() 246 gc.set_threshold(*thresholds) 247 248 # The following two tests are fragile: 249 # They precisely count the number of allocations, 250 # which is highly implementation-dependent. 251 # For example: 252 # - disposed tuples are not freed, but reused 253 # - the call to assertEqual somehow avoids building its args tuple 254 def test_get_count(self): 255 # Avoid future allocation of method object 256 assertEqual = self.assertEqual 257 gc.collect() 258 assertEqual(gc.get_count(), (0, 0, 0)) 259 a = dict() 260 # since gc.collect(), we created two objects: 261 # the dict, and the tuple returned by get_count() 262 assertEqual(gc.get_count(), (2, 0, 0)) 263 264 def test_collect_generations(self): 265 # Avoid future allocation of method object 266 assertEqual = self.assertEqual 267 gc.collect() 268 a = dict() 269 gc.collect(0) 270 assertEqual(gc.get_count(), (0, 1, 0)) 271 gc.collect(1) 272 assertEqual(gc.get_count(), (0, 0, 1)) 273 gc.collect(2) 274 assertEqual(gc.get_count(), (0, 0, 0)) 275 276 def test_trashcan(self): 277 class Ouch: 278 n = 0 279 def __del__(self): 280 Ouch.n = Ouch.n + 1 281 if Ouch.n % 17 == 0: 282 gc.collect() 283 284 # "trashcan" is a hack to prevent stack overflow when deallocating 285 # very deeply nested tuples etc. It works in part by abusing the 286 # type pointer and refcount fields, and that can yield horrible 287 # problems when gc tries to traverse the structures. 288 # If this test fails (as it does in 2.0, 2.1 and 2.2), it will 289 # most likely die via segfault. 290 291 # Note: In 2.3 the possibility for compiling without cyclic gc was 292 # removed, and that in turn allows the trashcan mechanism to work 293 # via much simpler means (e.g., it never abuses the type pointer or 294 # refcount fields anymore). Since it's much less likely to cause a 295 # problem now, the various constants in this expensive (we force a lot 296 # of full collections) test are cut back from the 2.2 version. 297 gc.enable() 298 N = 150 299 for count in range(2): 300 t = [] 301 for i in range(N): 302 t = [t, Ouch()] 303 u = [] 304 for i in range(N): 305 u = [u, Ouch()] 306 v = {} 307 for i in range(N): 308 v = {1: v, 2: Ouch()} 309 gc.disable() 310 311 def test_boom(self): 312 class Boom: 313 def __getattr__(self, someattribute): 314 del self.attr 315 raise AttributeError 316 317 a = Boom() 318 b = Boom() 319 a.attr = b 320 b.attr = a 321 322 gc.collect() 323 garbagelen = len(gc.garbage) 324 del a, b 325 # a<->b are in a trash cycle now. Collection will invoke 326 # Boom.__getattr__ (to see whether a and b have __del__ methods), and 327 # __getattr__ deletes the internal "attr" attributes as a side effect. 328 # That causes the trash cycle to get reclaimed via refcounts falling to 329 # 0, thus mutating the trash graph as a side effect of merely asking 330 # whether __del__ exists. This used to (before 2.3b1) crash Python. 331 # Now __getattr__ isn't called. 332 self.assertEqual(gc.collect(), 4) 333 self.assertEqual(len(gc.garbage), garbagelen) 334 335 def test_boom2(self): 336 class Boom2: 337 def __init__(self): 338 self.x = 0 339 340 def __getattr__(self, someattribute): 341 self.x += 1 342 if self.x > 1: 343 del self.attr 344 raise AttributeError 345 346 a = Boom2() 347 b = Boom2() 348 a.attr = b 349 b.attr = a 350 351 gc.collect() 352 garbagelen = len(gc.garbage) 353 del a, b 354 # Much like test_boom(), except that __getattr__ doesn't break the 355 # cycle until the second time gc checks for __del__. As of 2.3b1, 356 # there isn't a second time, so this simply cleans up the trash cycle. 357 # We expect a, b, a.__dict__ and b.__dict__ (4 objects) to get 358 # reclaimed this way. 359 self.assertEqual(gc.collect(), 4) 360 self.assertEqual(len(gc.garbage), garbagelen) 361 362 def test_boom_new(self): 363 # boom__new and boom2_new are exactly like boom and boom2, except use 364 # new-style classes. 365 366 class Boom_New(object): 367 def __getattr__(self, someattribute): 368 del self.attr 369 raise AttributeError 370 371 a = Boom_New() 372 b = Boom_New() 373 a.attr = b 374 b.attr = a 375 376 gc.collect() 377 garbagelen = len(gc.garbage) 378 del a, b 379 self.assertEqual(gc.collect(), 4) 380 self.assertEqual(len(gc.garbage), garbagelen) 381 382 def test_boom2_new(self): 383 class Boom2_New(object): 384 def __init__(self): 385 self.x = 0 386 387 def __getattr__(self, someattribute): 388 self.x += 1 389 if self.x > 1: 390 del self.attr 391 raise AttributeError 392 393 a = Boom2_New() 394 b = Boom2_New() 395 a.attr = b 396 b.attr = a 397 398 gc.collect() 399 garbagelen = len(gc.garbage) 400 del a, b 401 self.assertEqual(gc.collect(), 4) 402 self.assertEqual(len(gc.garbage), garbagelen) 403 404 def test_get_referents(self): 405 alist = [1, 3, 5] 406 got = gc.get_referents(alist) 407 got.sort() 408 self.assertEqual(got, alist) 409 410 atuple = tuple(alist) 411 got = gc.get_referents(atuple) 412 got.sort() 413 self.assertEqual(got, alist) 414 415 adict = {1: 3, 5: 7} 416 expected = [1, 3, 5, 7] 417 got = gc.get_referents(adict) 418 got.sort() 419 self.assertEqual(got, expected) 420 421 got = gc.get_referents([1, 2], {3: 4}, (0, 0, 0)) 422 got.sort() 423 self.assertEqual(got, [0, 0] + range(5)) 424 425 self.assertEqual(gc.get_referents(1, 'a', 4j), []) 426 427 def test_bug1055820b(self): 428 # Corresponds to temp2b.py in the bug report. 429 430 ouch = [] 431 def callback(ignored): 432 ouch[:] = [wr() for wr in WRs] 433 434 Cs = [C1055820(i) for i in range(2)] 435 WRs = [weakref.ref(c, callback) for c in Cs] 436 c = None 437 438 gc.collect() 439 self.assertEqual(len(ouch), 0) 440 # Make the two instances trash, and collect again. The bug was that 441 # the callback materialized a strong reference to an instance, but gc 442 # cleared the instance's dict anyway. 443 Cs = None 444 gc.collect() 445 self.assertEqual(len(ouch), 2) # else the callbacks didn't run 446 for x in ouch: 447 # If the callback resurrected one of these guys, the instance 448 # would be damaged, with an empty __dict__. 449 self.assertEqual(x, None) 450 451class GCTogglingTests(unittest.TestCase): 452 def setUp(self): 453 gc.enable() 454 455 def tearDown(self): 456 gc.disable() 457 458 def test_bug1055820c(self): 459 # Corresponds to temp2c.py in the bug report. This is pretty 460 # elaborate. 461 462 c0 = C1055820(0) 463 # Move c0 into generation 2. 464 gc.collect() 465 466 c1 = C1055820(1) 467 c1.keep_c0_alive = c0 468 del c0.loop # now only c1 keeps c0 alive 469 470 c2 = C1055820(2) 471 c2wr = weakref.ref(c2) # no callback! 472 473 ouch = [] 474 def callback(ignored): 475 ouch[:] = [c2wr()] 476 477 # The callback gets associated with a wr on an object in generation 2. 478 c0wr = weakref.ref(c0, callback) 479 480 c0 = c1 = c2 = None 481 482 # What we've set up: c0, c1, and c2 are all trash now. c0 is in 483 # generation 2. The only thing keeping it alive is that c1 points to 484 # it. c1 and c2 are in generation 0, and are in self-loops. There's a 485 # global weakref to c2 (c2wr), but that weakref has no callback. 486 # There's also a global weakref to c0 (c0wr), and that does have a 487 # callback, and that callback references c2 via c2wr(). 488 # 489 # c0 has a wr with callback, which references c2wr 490 # ^ 491 # | 492 # | Generation 2 above dots 493 #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . 494 # | Generation 0 below dots 495 # | 496 # | 497 # ^->c1 ^->c2 has a wr but no callback 498 # | | | | 499 # <--v <--v 500 # 501 # So this is the nightmare: when generation 0 gets collected, we see 502 # that c2 has a callback-free weakref, and c1 doesn't even have a 503 # weakref. Collecting generation 0 doesn't see c0 at all, and c0 is 504 # the only object that has a weakref with a callback. gc clears c1 505 # and c2. Clearing c1 has the side effect of dropping the refcount on 506 # c0 to 0, so c0 goes away (despite that it's in an older generation) 507 # and c0's wr callback triggers. That in turn materializes a reference 508 # to c2 via c2wr(), but c2 gets cleared anyway by gc. 509 510 # We want to let gc happen "naturally", to preserve the distinction 511 # between generations. 512 junk = [] 513 i = 0 514 detector = GC_Detector() 515 while not detector.gc_happened: 516 i += 1 517 if i > 10000: 518 self.fail("gc didn't happen after 10000 iterations") 519 self.assertEqual(len(ouch), 0) 520 junk.append([]) # this will eventually trigger gc 521 522 self.assertEqual(len(ouch), 1) # else the callback wasn't invoked 523 for x in ouch: 524 # If the callback resurrected c2, the instance would be damaged, 525 # with an empty __dict__. 526 self.assertEqual(x, None) 527 528 def test_bug1055820d(self): 529 # Corresponds to temp2d.py in the bug report. This is very much like 530 # test_bug1055820c, but uses a __del__ method instead of a weakref 531 # callback to sneak in a resurrection of cyclic trash. 532 533 ouch = [] 534 class D(C1055820): 535 def __del__(self): 536 ouch[:] = [c2wr()] 537 538 d0 = D(0) 539 # Move all the above into generation 2. 540 gc.collect() 541 542 c1 = C1055820(1) 543 c1.keep_d0_alive = d0 544 del d0.loop # now only c1 keeps d0 alive 545 546 c2 = C1055820(2) 547 c2wr = weakref.ref(c2) # no callback! 548 549 d0 = c1 = c2 = None 550 551 # What we've set up: d0, c1, and c2 are all trash now. d0 is in 552 # generation 2. The only thing keeping it alive is that c1 points to 553 # it. c1 and c2 are in generation 0, and are in self-loops. There's 554 # a global weakref to c2 (c2wr), but that weakref has no callback. 555 # There are no other weakrefs. 556 # 557 # d0 has a __del__ method that references c2wr 558 # ^ 559 # | 560 # | Generation 2 above dots 561 #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . 562 # | Generation 0 below dots 563 # | 564 # | 565 # ^->c1 ^->c2 has a wr but no callback 566 # | | | | 567 # <--v <--v 568 # 569 # So this is the nightmare: when generation 0 gets collected, we see 570 # that c2 has a callback-free weakref, and c1 doesn't even have a 571 # weakref. Collecting generation 0 doesn't see d0 at all. gc clears 572 # c1 and c2. Clearing c1 has the side effect of dropping the refcount 573 # on d0 to 0, so d0 goes away (despite that it's in an older 574 # generation) and d0's __del__ triggers. That in turn materializes 575 # a reference to c2 via c2wr(), but c2 gets cleared anyway by gc. 576 577 # We want to let gc happen "naturally", to preserve the distinction 578 # between generations. 579 detector = GC_Detector() 580 junk = [] 581 i = 0 582 while not detector.gc_happened: 583 i += 1 584 if i > 10000: 585 self.fail("gc didn't happen after 10000 iterations") 586 self.assertEqual(len(ouch), 0) 587 junk.append([]) # this will eventually trigger gc 588 589 self.assertEqual(len(ouch), 1) # else __del__ wasn't invoked 590 for x in ouch: 591 # If __del__ resurrected c2, the instance would be damaged, with an 592 # empty __dict__. 593 self.assertEqual(x, None) 594 595def test_main(): 596 enabled = gc.isenabled() 597 gc.disable() 598 assert not gc.isenabled() 599 debug = gc.get_debug() 600 gc.set_debug(debug & ~gc.DEBUG_LEAK) # this test is supposed to leak 601 602 try: 603 gc.collect() # Delete 2nd generation garbage 604 run_unittest(GCTests, GCTogglingTests) 605 finally: 606 gc.set_debug(debug) 607 # test gc.enable() even if GC is disabled by default 608 if verbose: 609 print "restoring automatic collection" 610 # make sure to always test gc.enable() 611 gc.enable() 612 assert gc.isenabled() 613 if not enabled: 614 gc.disable() 615 616if __name__ == "__main__": 617 test_main()