代码之家  ›  专栏  ›  技术社区  ›  Staale

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

  •  1
  • Staale  · 技术社区  · 17 年前

    以这种方式加载:

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

    问题是,像这样加载多个类会导致对象出现在垃圾回收的不可回收部分,即实际的类定义中。我也可以将其加载到全局字典中,但问题仍然是孤立类。有什么方法可以卸载这些类吗?

    主要的问题是课堂。 物料需求计划 属性,其中包含对类本身的引用,导致垃圾回收器无法处理的循环引用。

    这里有一个小的测试用例供您自己查看:

    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 回复  |  直到 17 年前
        1
  •  1
  •   Ants Aasma    17 年前

    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
    
        2
  •  1
  •   workmad3    17 年前

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

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

    否则,将出现对类对象的非循环引用,这将阻止其被清理。