python - 删除对象后成员变量的引用计数不减少
问题描述
背景真相(?):当python程序退出时,gc
(garbage collection
)以一种常见的方式收集内存reference counting
。
所以当一个对象被删除时,它的成员对象的引用计数应该减1。但我发现引用计数不会减1,除非del
在__del__
函数中调用
import sys
class B():
def __init__(self):
self.name = 'little b construct'
def __del__(self):
print(sys.getrefcount(self))
print('little b was deleted')
class A():
def __init__(self):
print('little a construct')
self._b = B()
def __del__(self):
# del self._b # makes B' reference minus 1
print('little a was deleted')
if __name__ == '__main__':
a = A()
结果:
# without del self._b
little a construct
little a was deleted
4
little b was deleted
# with del self._b
little a construct
3
little b was deleted
little a was deleted
问题:
为什么删除 A 后 B 的引用计数不会自动减 1?
B的引用计数是由什么
4
组成的?
谢谢你的帮助
解决方案
我已经简化了你的例子,以便更容易在心里计算参考。
发生的情况是,您必须计算对象的引用,方法内的 self 的引用,以及在调用时运行的任何函数调用的参数中对同一对象的其他引用sys.getrefcount
,包括该函数,因为它还在自己的本地范围内保存了引用的副本。
因此,您缺少的是调用函数,需要将对象作为参数传递,使新名称绑定到本地函数/方法范围内的形式参数。总是有一个+1的偏移量,即使你只有一个指向对象的名称,正是因为这个新的本地引用 inside sys.getrefcount
:
import sys
class B():
def __init__(self):
print('setting up b...')
def counter(self):
return sys.getrefcount(self)
class A():
def __init__(self):
print('setting up a...')
if __name__ == '__main__':
a = A()
b = B()
print(sys.getrefcount(a))
print(sys.getrefcount(b))
print(b, b.counter()) # 5 refs to b. Why 5?
print(b, B.counter(b)) # Because this is what really happens.
print(b.counter(), b ) # 4 refs to b
print(b,b,b.counter()) # 6 refs to b
输出:
setting up a...
setting up b...
2
2
<__main__.B object at 0x7f11df905940> 5
4 <__main__.B object at 0x7f11df905940>
<__main__.B object at 0x7f11df905940> <__main__.B object at 0x7f11df905940> 6
除此之外,这__init__
不是构造函数,那__new__
是您通常不需要的,__init__
设置已创建并可通过 访问的对象self
,请参阅我的另一个答案here,__del__
通常也不需要,除非您需要一些特殊的资源清理只是在对象销毁之前(不需要销毁包含的对象)。
最后 del不会删除一个对象,它只是删除一个绑定到它的名称;它会减少 refcount,并且在 refcount 达到 0 后,它最终会被 GC 收集。
我对 Q1 的解释是它a
仍然存在。__del__
正如您在文档的评论链接中提到的,__del__
终结器不是析构函数。Refcount 是0
意味着__del__
被调用,并不意味着对象被销毁,__del__
也不会销毁它。因此,您打印的消息不准确(到破坏时刻)。它会被 GC 销毁,但你不知道确切的时间(语言中没有指定,取决于实现)。
实验替换语句
a = A()
只是
A()
然后不保留对 A() 对象的引用,这也会将您的引用计数减少b
一(同时保持输出的其余部分相同),这意味着不再有a._b
. 所以应该是a
内存中的存在a._b
解释了这个 4 而不是 3.a
在运行时仍然存在B.__del__
。del a
如果您改为添加 a作为最后一条语句,也会发生同样的情况(b 的计数减少) 。
推荐阅读
- php - 如果列 B 的值小于 700,则 phpspreadsheet 条件格式列 A
- python - Python如何从嵌套循环中返回嵌套字典?
- sql-server - 在 SSAS 表格中使用动态行过滤器进行动态数据屏蔽
- sql - 如果结果是正数和负数,如何从多列中求和并分离到单独的列中
- java - 如何获取log4j2中所有记录器的列表
- laravel - 无法使用 SendGrid 中的 2 个可能的身份验证器在用户名“apikey”的 SMTP 服务器上进行身份验证
- mysql - Mysql 5.7 - 从子选择中获取多个值
- r - 如何使用 for 循环找到两行的平均值?
- cassandra - Apache Beam - 将 BigQuery TableRow 写入 Cassandra
- slider - 在 Power BI 中对公历日期进行排序