I am writing a simple platform game, and I've found that when removing 'ghost' instances, they persist and are not garbage collected. It seems that although I am removing all references, the ghost objects have some kind of internal references that are preventing them being garbage collected. Specifically they have attributes which are method switches.
The following code illustrates my problem:
import weakref
weak_ghosts = weakref.WeakKeyDictionary()
class Ghost(object):
def __init__(self):
#pass
self.switch = {'eat':self.eat, 'sleep':self.sleep}
def eat(self):
pass
def sleep(self):
pass
ghost = Ghost()
weak_ghosts[ghost] = None
#ghost.switch = {} # uncomment this line and ghost is successfully removed
del ghost
print "number of ghosts =", len(weak_ghosts)
#output:
number of ghosts = 1
Questions:
The garbage collector cannot collect an object in use by an application while the application's code can reach that object. The application is said to have a strong reference to the object. A weak reference permits the garbage collector to collect the object while still allowing the application to access the object.
They aren’t looking for things to delete, they know exactly what has to be removed. Garbage collection is a method to free the programmer from worrying about basic memory management. It isn’t the only option; simple reference counting also covers the vast majority of memory management needs.
Garbage collection is performed automatically. We cannot force or prevent it. Objects are retained in memory while they are reachable. Being referenced is not the same as being reachable (from a root): a pack of interlinked objects can become unreachable as a whole, as we’ve seen in the example above.
Garbage collection has to scan memory, thus its complexity must be a function of N, where N may be the number of bytes or the number of objects. It must be bound by a linear function of N, since ultimately it needs to scan all of these objects.
There is a circular reference created by self.switch
referencing the object it's part of. Check this out:
import weakref
class Ghost(object):
def __init__(self):
#pass
self.switch = {'eat':self.eat, 'sleep':self.sleep}
def eat(self):
pass
def sleep(self):
pass
ghost = Ghost()
def callback(o):
print 'callback', o
wref = weakref.ref(ghost, callback)
print 'del ghost'
del ghost
print 'after del ghost'
Prints:
del ghost
after del ghost
callback <weakref at 00B55FC0; dead>
So the actual object was just cleaned on shutdown.
You can run the GC manually to see the effect. Add this to the end of the script above:
print 'gc.collect'
import gc
gc.collect()
print 'after gc.collect'
Now you'll see:
del ghost
after del ghost
gc.collect
callback <weakref at 00B55FC0; dead>
after gc.collect
Note that by default, this GC is enabled and will run from time to time. It will clean up your ghost
objects because they become unreachable circular references.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With