在python中,如何卸载生成的类

时间:2009-05-28 09:12:56

标签: python dynamic garbage-collection classloader

我正在开发一个将文件(hfd5 - pytables)加载到对象结构中的库。用于结构的实际类从hdf5文件加载为字符串,然后 以这种方式加载:

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)

请注意:我已经反对使用解析文件中的文本来更早地创建类,但显然他们已经开始在这里使用它并看到我没有的一些好处,所以远离这个解决方案是没有'现在可行。

2 个答案:

答案 0 :(得分:1)

我认为GC可以处理循环引用,但是您需要做的是从globals()dict中删除引用:

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

否则会有一个非循环引用类对象,它将阻止它被清理。

答案 1 :(得分: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