__del__() 如何干扰垃圾回收?

2024-03-04

I read :

class Account(object):
    def __init__(self,name,balance):
         self.name = name
         self.balance = balance
         self.observers = set()
    def __del__(self):
         for ob in self.observers:
             ob.close()
         del self.observers
    def register(self,observer):
        self.observers.add(observer)
    def unregister(self,observer):
        self.observers.remove(observer)
    def notify(self):
        for ob in self.observers:
            ob.update()
    def withdraw(self,amt):
        self.balance -= amt
        self.notify()

class AccountObserver(object):
     def __init__(self, theaccount):
         self.theaccount = theaccount
         theaccount.register(self)
     def __del__(self):
         self.theaccount.unregister(self)
         del self.theaccount
     def update(self):
         print("Balance is %0.2f" % self.theaccount.balance)
     def close(self):
         print("Account no longer in use")

# Example setup
a = Account('Dave',1000.00)
a_ob = AccountObserver(a)

值得一提的是

...这些类创建了一个引用循环,其中引用计数永远不会降至 0,并且不会进行清理。不仅如此,垃圾收集器(gcmodule)甚至不会清理它,从而导致永久性内存泄漏。

有人可以解释这是如何发生的吗?弱引用在这里有何帮助?


Account().observers是一个集合引用AccountObserver()实例,但是AccountObserver().theaccount是一个参考指向back to the Account()观察者存储在集合中的实例。这是一个循环引用。

通常,垃圾收集器会检测到此类循环并中断循环,从而使引用计数降至 0 并进行正常清理。然而,对于定义了__del__方法,就像 David 示例中的类所做的那样。来自蟒蛇2gc模块文档 https://docs.python.org/2/library/gc.html#gc.garbage:

gc.garbage
收集器发现无法访问但无法释放的对象列表(无法收集的对象)。默认情况下,此列表仅包含具有__del__()方法。具有的对象__del__()方法 和 是引用循环的一部分导致整个引用循环无法收集,包括不一定在循环中但只能从循环中访问的对象。 Python 不会自动收集此类循环,因为一般来说,Python 不可能猜测运行该程序的安全顺序。__del__()方法。

所以这个循环不能被打破,因为垃圾收集器拒绝猜测终结器(__del__方法)首先调用。请注意,随机选择一个是not safe对于具体的例子;如果你打电话Account().__del__首先,然后是observersset 被删除,后续调用AccountObserver().__del__将会失败AttributeError.

弱引用不参与引用计数;因此,如果AccountObserver().theaccount使用弱引用来指向相应的Account()实例代替,然后Account()如果仅留下弱引用,实例将不会保持活动状态:

class AccountObserver(object):
    def __init__(self, theaccount):
        self.theaccountref = weakref.ref(theaccount)
        theaccount.register(self)

    def __del__(self):
        theaccount = self.theaccountref()
        if theaccount is not None:    
            theaccount.unregister(self)

    def update(self):
        theaccount = self.theaccountref()
        print("Balance is %0.2f" % theaccount.balance)

    def close(self):
        print("Account no longer in use")

请注意,我链接到了 Python 2 文档。从 Python 3.4 开始,这不再是正确的,甚至是循环依赖,如示例所示will被清除,如PEP 442 – 安全对象终结 https://www.python.org/dev/peps/pep-0442/已实施:

此 PEP 的主要优点涉及具有终结器的对象,例如具有终结器的对象__del__方法和带有finally 块的生成器。现在,当这些对象属于引用循环的一部分时,可以回收它们。

这并不是说这不会导致回溯;如果您在 Python 3.6 中执行示例,删除引用并启动垃圾收集运行,您将得到一个回溯Account().observers设置可能已被删除:

>>> import gc
>>> del a, a_ob
>>> gc.collect()
Account no longer in use
Exception ignored in: <bound method AccountObserver.__del__ of <__main__.AccountObserver object at 0x10e36a898>>
Traceback (most recent call last):
  File "<stdin>", line 6, in __del__
  File "<stdin>", line 13, in unregister
AttributeError: 'Account' object has no attribute 'observers'
65

回溯只是一个警告,否则,gc.collect()呼叫成功,僵尸AccountObserver() and Account()无论如何,物体都会被收获。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

__del__() 如何干扰垃圾回收? 的相关文章

随机推荐

  • Control.MonadPlus.Free,无需不必要的分发

    我正在尝试使用免费的 monad 构建 EDSL 用于构建像 Prolog 这样的 AND OR 决策树 其中 gt gt 映射到 AND 并且mplus映射到 OR 我希望能够描述类似的东西A AND B OR C AND D OR E
  • 子窗口关闭时如何运行父窗口的功能?

    我正在调用 javascript window open 函数来在弹出窗口中加载另一个网址 用户完成操作后 会将他们带到最后一页 其中有一个链接 其中显示调用 window close 函数的关闭窗口 现在 当该页面关闭时 我需要更新打开窗
  • 我可以从 Firebase 远程配置的默认值获取 JSONObject

    我需要取JSONObject从远程的默认值config in Firebase By FirebaseRemoteConfig getString 它被转换为字符串 但不是在JSONObject 说 org json JSONExcepti
  • 无法使用 tsc 节点模块编译打字稿

    我正在尝试使用 tsc 节点包模块将打字稿编译为 JavaScript 首先 我使用安装了该模块npm install g typescript 在我的本地目录中 我创建了一个名为classes js 的文件 其中包含有效的打字稿代码 跑步
  • Neo4j 服务器与嵌入式模式

    我想确切地知道 neo4j 服务器和嵌入式模式是什么意思 即使我浏览了该帖子Neo4j 服务器与嵌入式 https stackoverflow com questions 8224523 neo4j server vs embedded 但
  • 使用 HTTP/2 时,缩小和连接 JS/CSS 文件以及使用图像精灵是否仍能提供性能优势?

    使用新的 HTTP 2 协议 向同一服务器重复 HTTP 请求所产生的开销已大大减少 考虑到这一点 缩小和连接 JavaScript CSS 文件以及将图像组合成精灵是否仍然具有任何显着的性能优势 或者当使用 HTTP 2 时这些做法不再有
  • EventSourced Saga 实施

    我已经编写了一个事件源聚合 现在实现了一个事件源传奇 我注意到两者是相似的 并创建了一个事件源对象作为两者派生的基类 我在这里看过一个演示http blog jonathanoliver com cqrs sagas with event
  • Android 手机启动时广播接收器不工作

    我为 ICS 创建了一个锁屏 并将其放置在框架中 我们可以使用它打开应用程序 对于用户效果 我在显示锁定屏幕时启动了动画 该动画是使用 SCREEN ON 广播接收器启动的 但是当手机启动时 即使我注册了广播接收器 它也没有到达 onRec
  • 与使用数据库相比,经典 ASP 和 PHP 之间共享会话

    我们有一个经过多年开发的 ASP 内联网 Web 应用程序 它在 IIS6 上运行 如今 我们希望使用 PHP 语言来添加一些新功能 PHP 在同一台服务器上运行良好 会话变量需要在 ASP 和 PHP 之间共享 我问是否有其他替代方案可以
  • 标记模板文字的 TemplateObject 数组是否被其领域弱引用?

    while c tag str0 e str1 JavaScript 运行时创建一个冻结数组 例如Object freeze str0 str1 但还有一个额外的 raw财产 可以使用该对象作为 a 中的键吗 WeakMap以避免每次循环时
  • 需要 Angular 2 ng

    我在 Angular 2 中制作了一个模型驱动表单 并且只有在未选中上面的复选框时才必须显示其中一个输入字段 我使用 ngIf 执行此操作 我的问题是 仅当未选中该复选框时 如何设置所需的输入 在 Angular 1 x 中 我可以通过视图
  • 递归 XSLT,第 2 部分

    好的 继续我的问题here https stackoverflow com questions 2907332 how can i write an xslt that will recursively include other file
  • 经常将 IRB 历史记录刷新到文件

    irb 可以将命令历史记录写入文件 但只有在 irb 会话结束时才会执行此操作 我想更频繁地写出我的命令历史记录 与每个命令 如 shell 历史记录 一样频繁 但不必如此频繁 是否有 irbrc 设置 或者我必须破解 irb 源 已经多次
  • 将鼠标悬停在图像上方的 Font Awesome 图标居中

    当鼠标悬停在图像上时 我试图将字体很棒的图标置于图像的中心 这是我的 HTML div class profile img container img src http s3 amazonaws com 37assets svn 765 d
  • 如何在 Xamarin Forms 中将 Android 日期选择器设置为微调器(而非日历)模式?

    在 Android 设备上的 Xamarin Forms 中选择日期选择器控件时 将显示日期选择器的日历模式视图 如何更改它以显示微调模式 我找到的唯一示例是更新我的 styles xml 这是我所拥有的 但不起作用
  • CSS 不同的链接样式

    据我所知 使用类似的东西 class a 与使用相同 class a link Right 另外 以下两种款式是一样的吗 class a focus class a hover 最后 下面的样式是鼠标按下时的颜色吧 class a acti
  • Zend Framework 2 - Hydrator 策略未响应且水合

    我基本上实现了这个策略 https github com zendframework zf2 pull 2072 主要区别是 我猜 我使用Doctrine2 调用构造函数类 打印测试回显 但两个函数extract and hydrate 不
  • LINQ:将 lambda 表达式作为参数传递以由方法执行和返回

    因此 场景如下 我有一系列不同的存储库类 每个类都可以使用独立的数据上下文或共享上下文 在使用隔离上下文的情况下 我想向基类添加一个方法 该方法允许我将 lambda 指定为参数 让该表达式由所选存储库的隔离上下文执行并返回 IQuerya
  • 如何设置 Bitmap.Width 和 Bitmap.height

    您好 我已经加载了位图 我需要设置自己的高度和宽度 bitmap height 100 但这个声明不允许我 因为它说 System Drawing Image Width cannot be assigned to it is read o
  • __del__() 如何干扰垃圾回收?

    I read class Account object def init self name balance self name name self balance balance self observers set def del se