我的方法是否适合收集圆形参考物体的gargabe?

时间:2015-11-17 16:35:34

标签: python garbage-collection weak-references circular-reference

当我玩新创建的html模块时,我使用了weakref模块来克服循环引用问题。对我来说一切似乎都没问题!但我不确定我遵循的方式,也不确定下面的Scope课程。我尝试了一个最小的工作示例(这里是完整代码的link)。 Html类仅用于使用python对象创建html输出。当然,下面的例子并不是为了简单起见。

# encoding: utf-8
from __future__ import print_function, unicode_literals
import weakref


class Scope(object):
    def __init__(self):
        self.ref_holder = set()

    def add(self, obj):
        self.ref_holder.add(obj)

    def __enter__(self):
        return self

    def __exit__(self, *args, **kwargs):
        self.ref_holder = None


class Html(object):
    def __init__(self, parent=None, tag="", scope=None):
        self.scope = scope
        if parent is None:
            self.parent = None
        elif type(parent) != weakref.CallableProxyType:
            self.parent = weakref.proxy(parent)
            if self.scope:
                self.scope.add(parent)
            elif parent.scope:
                parent.scope.add(self)
        else:
            self.parent = parent
        self.tag = tag
        if self.scope:
            self.scope.add(self)
        self.children = []

    def append(self, html):
        if isinstance(html, basestring):
            html = Html(tag=html)
            return self.append(html)
        elif isinstance(html, self.__class__):
            self.children.append(html)
            return html
        else:
            raise Exception("Unknown type")

    def __unicode__(self):
        return 'Html "{tag}" children = {children}'.format(tag=self.tag,
                                            children=list(map(str, self.children)))

    def __str__(self):
        return self.__unicode__()

if __name__ == "__main__":
    with Scope() as scope:
        test_form = Html(tag="form", scope=scope)
        test_form.append(Html(tag="label"))
        test_input = Html(tag="input")
        test_form.append(test_input)
        print(test_form)

以下是我的疑虑,我将非常感谢您的指导:

我将引用持有者类称为Scope。它只保存对象的引用,即使它们没有分配给任何变量,因此Html对象不会被垃圾收集(注意:某些对象可以更改父/子关系,因此没有任何对对象的强引用,在实际代码中。)

我可以简单地在列表中保存对象引用并在此之后删除它,但使用with语句似乎更好。类名Scope是否适合此任务以及我持有引用的方式是正确的?是否有一种很好的方法来保持动态创建的对象的强引用与我的方法不同?

我相信在退出with语句后将Scope.ref_holder变量设置为None,释放所有强引用,然后gc收集它们。我通过禁用gc和调用gc.collect测试了这个,然后没有对象存在不可用,我是否正确地假设这种方法确保没有泄漏?

修改

  1. 我添加了link完整源代码。
  2. 代码符合 Python 2.7

2 个答案:

答案 0 :(得分:1)

我认为这里的重点是您在Python中使用与feed_dict匹配的session.run(fetches,feed_dict=None)

基本上不应该这样发生。在__exit__您要返回自我,with应删除所有引用。你确定你中间没有任何例外吗?由于异常__enter__可能返回false,您的垃圾回收可能不完整。

然而,为了回答您的问题,我可以告诉您,__exit__方法中__exit__的方式是强制垃圾清理&我认为这完全取决于操作系统。如果None以某种方式与这些对象的地址相关,则可以正确清理它们。

尝试__exit__。确保更强大的清理。

答案 1 :(得分:1)

也许有点OT:为什么明确的范围类?

更简单的事情呢?

@contextlib.contextmanager
def scope():
    rv = set()
    try:
        yield rv
    finally:
        pass
        # if you must be explicit or 
        # if you want side-effect in leaked scopes
        rv.clear()