内部引用可防止垃圾回收

fra*_*xel 7 python garbage-collection initialization

我正在编写一个简单的平台游戏,我发现在删除'ghost'实例时,它们会持续存在并且不会被垃圾收集.似乎虽然我删除了所有引用,但ghost对象有一些内部引用,阻止它们被垃圾收集.具体来说,它们具有方法切换的属性.

以下代码说明了我的问题:

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
Run Code Online (Sandbox Code Playgroud)

问题:

  1. 究竟发生了什么?
  2. 我该怎么做才能避免这种情况?
  3. 我是否使用正确的方法制作可切换的方法词典?

Eli*_*sky 4

self.switch通过引用它所属的对象创建了一个循环引用。看一下这个:

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'
Run Code Online (Sandbox Code Playgroud)

印刷:

del ghost
after del ghost
callback <weakref at 00B55FC0; dead>
Run Code Online (Sandbox Code Playgroud)

所以实际的物体只是在关机时被清理了。

您可以手动运行GC看看效果。将其添加到上面脚本的末尾:

print 'gc.collect'
import gc
gc.collect()
print 'after gc.collect'
Run Code Online (Sandbox Code Playgroud)

现在你会看到:

del ghost
after del ghost
gc.collect
callback <weakref at 00B55FC0; dead>
after gc.collect
Run Code Online (Sandbox Code Playgroud)

请注意,默认情况下,此 GC 处于启用状态并且会不时运行。它将清理你的ghost对象,因为它们变成了无法访问的循环引用。