2009-05-28 6 views
1

Я работаю над библиотекой, которая загружает файлы (hfd5 - pytables) в структуру объекта. Фактические классы используются для структуры загружается в виде строки из файла hdf5, а затем загружен таким образом:В python, как вы можете разгрузить сгенерированные классы

class NamespaceHolder(dict): 
    # stmt is the source code holding all the class defs 
    def execute(self, stmt): 
     exec stmt in self 

Проблема, загрузка нескольких классов, как это, заставляет объекты появляться в невозвратные часть коллекции мусора, а именно фактические определения классов. Я также могу загрузить это в глобальный словарь, но проблема остается в сиротских классах. Есть ли способ разгрузить классы?

Основная проблема - класс. mro атрибут, который содержит ссылку на сам класс, вызывая круговые ссылки, которые сборщик мусора не может обрабатывать.

Вот небольшой тест, чтобы увидеть для себя:

import gc 

if __name__ == "__main__": 
    gc.enable() 
    gc.set_debug(gc.DEBUG_LEAK) 

    code = """ 
class DummyA(object): 
    pass 
""" 
    context = {} 

    exec code in context 
    exec code in context 

    gc.collect() 
    print len(gc.garbage) 

Только примечание: я уже приводил доводы против использования разбора от текста в файле для создания классов ранее, но, видимо, они настроены на использование это здесь и увидеть некоторые преимущества, которых я не знаю, поэтому уйти от этого решения сейчас не представляется возможным.

+0

Собственно, уход из этого не-решения всегда возможен. Если он загромождает память безвозвратным мусором, он не работает. –

+0

Я помню, где-то читал (comp.lang.python? Список Python-Dev? Не помню, где), что основная команда разработчиков полностью знает тот факт, что объекты класса не могут быть собраны, а IIRC Guido сказал: «Если вы «динамически создавая в вашем коде тысячи классов, что-то не так с вашим алгоритмом», но ICBW. – tzot

ответ

1

gc.set_debug (gc.DEBUG_LEAK) вызывает утечку. Попробуйте следующее:

import gc 

def foo():        
    code = """ 
class DummyA(object): 
    pass    
""" 
    context = {} 
    exec code in context 
    exec code in context 

    gc.collect() 
    print len(gc.garbage), len(gc.get_objects()) 

gc.enable() 
foo(); foo() # amount of objects doesn't increase 
gc.set_debug(gc.DEBUG_LEAK) 
foo() # leaks 
+0

Большое спасибо. Однако я заметил, что все мои утечки исчезли, когда я выключил gc.DEBUG_LEAK – Staale

1

Я думаю, что GC может справиться с циклическими ссылками, однако вам нужно сделать, это удалить ссылку из глобал() ДИКТ:

try: 
    del globals()['DummyA'] 
except KeyError: 
    pass 

иначе будет некруглая ссылка на объект класса, который остановит его очистку.

+0

Взгляните на http://stackoverflow.staale.org/919924.png Это циклический график, который исходит от запуска вышеуказанного кода. Указанный здесь кортеж содержит (DummyA, object) и не может быть удален или изменен, и поэтому класс DummyA не может быть собран – Staale

 Смежные вопросы

  • Нет связанных вопросов^_^