внутренняя ссылка предотвращает сборку мусора - PullRequest
7 голосов
/ 17 февраля 2012

Я пишу простую платформенную игру и обнаружил, что при удалении экземпляров-призраков они сохраняются и не собираются сборщиком мусора.Кажется, что хотя я удаляю все ссылки, объекты-призраки имеют какие-то внутренние ссылки, которые не позволяют собирать мусор.В частности, они имеют атрибуты, которые являются переключателями методов.

Следующий код иллюстрирует мою проблему:

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

Вопросы:

  1. Что на самом деле происходит?
  2. Что мне делать, чтобы избежать этой ситуации?
  3. Использую ли я правильную методологию для создания переключаемого словаря методов?

Ответы [ 2 ]

4 голосов
/ 17 февраля 2012

Существует круговая ссылка, созданная 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'

Отпечатки:

del ghost
after del ghost
callback <weakref at 00B55FC0; dead>

Таким образом, фактический объект был просто очищен при выключении.

Вы можете запустить ГХ вручную, чтобы увидеть эффект,Добавьте это в конец приведенного выше сценария:

print 'gc.collect'
import gc
gc.collect()
print 'after gc.collect'

Теперь вы увидите:

del ghost
after del ghost
gc.collect
callback <weakref at 00B55FC0; dead>
after gc.collect

Обратите внимание, что по умолчанию этот GC включен и будет работать время от времени,Это очистит ваши ghost объекты, потому что они становятся недоступными циклическими ссылками.

2 голосов
/ 17 февраля 2012

Можно сделать следующее:

class Ghost(object):
    def __init__(self):
        self.switch = {'eat':Ghost.eat, 'sleep':Ghost.sleep}

Таким образом, методы остаются несвязанными.

...