python中del、垃圾回收和弱引用

对象绝不会自行销毁;然而,无法得到对象时,可能会被当作垃圾回收。

—— Python语言参考手册中“Data Model”一章。

del、垃圾回收

del语句删除名称,而不是对象
del命令可能会导致对象被当作垃圾回收,但是仅当删除的变量保存的是对象的最后一个引用,或者无法得到对象时。重新绑定也可能会导致对象的引用数量归零,导致对象被销毁。

在CPython中,垃圾回收使用的主要算法是引用计数。实际上,每个对象都会统计有多少引用指向自己。当引用计数归零时,对象立即就被销毁:CPython会在对象上调__del__方法(如果定义了),然后释放分配给对象的内存。

Python的其他实现有更复杂的垃圾回收程序,而且不依赖引用计数,这意味着,对象的引用数量为零时可能不会立即调用__del__方法。

为了演示对象生命结束时的情形,示例1使用weakref.finalize注册一个回调函数,在销毁对象时调用。

#示例1:没有指向对象的引用时,监视对象生命结束时的情形
>>> import weakref 
>>> s1 = {1, 2, 3} 
>>> s2 = s1        #➊ 
>>> def bye():     #➋ 
...     print('Gone with the wind...') 
... 
>>> ender = weakref.finalize(s1, bye)  #➌ 
>>> ender.alive  #➍ 
True 
>>> del s1 
>>> ender.alive  #➎ 
True 
>>> s2 = 'spam'  #➏ 
Gone with the wind... 
>>> ender.alive 
False

➊ s1和s2是别名,指向同一个集合,{1, 2, 3}。
➋ 这个函数一定不能是要销毁的对象的绑定方法,否则会有一个指向对象的引用。
➌ 在s1引用的对象上注册bye回调。
➍ 调用finalize对象之前,.alive属性的值为True。
➎ 如前所述,del不删除对象,而是删除对象的引用。
➏ 重新绑定最后一个引用s2,让{1, 2, 3}无法获取。对象被销毁了,调用了bye回调,ender.alive的值变成了False。

示例1的目的是:明确指出del不会删除对象,但是执行del操作后可能会导致对象不可获取,从而被删除

为什么示例1的{1, 2, 3}对象被销毁了?毕竟,我们把s1引用传给finalize函数了,而为了监控对象和调用回调,必须要有引用。这是因为,finalize持有{1, 2, 3}的弱引用。

弱引用

正是因为有引用,对象才会在内存中存在。当对象的引用数量归零后,垃圾回收程序会把对象销毁。但是,有时需要引用对象,而不让对象存在的时间超过所需时间。这经常用在缓存中。

  • 弱引用不会增加对象的引用数量。引用的目标对象称为所指对象(referent)。因此我们说,弱引用不会妨碍所指对象被当作垃圾回收。
  • 弱引用在缓存应用中很有用,因为不想仅因为被缓存引用着而始终保存缓存对象。

示例2展示了如何使用weakref.ref实例获取所指对象。如果对象存在,调用弱引用可以获取对象;否则返回None。

#示例2:弱引用是可调用的对象,返回的是被引用的对象;如果所指对象不存在了,
返回None
>>> import weakref 
>>> a_set = {0, 1} 
>>> wref = weakref.ref(a_set)  #➊ 
>>> wref
><weakref at 0x100637598; to 'set' at 0x100636748> 
>>> wref()  #➋ 
{0, 1} 
>>> a_set = {2, 3, 4}  #➌ 
>>> wref()  #➍ 
{0, 1} 
>>> wref() is None  #➎ 
False 
>>> wref() is None  #➏ 
True

➊ 创建弱引用对象wref,下一行审查它。
➋ 调用wref()返回的是被引用的对象,{0, 1}。因为这是控制台会话,所以{0, 1}会绑定给_变量。
➌ a_set不再指代{0, 1}集合,因此集合的引用数量减少了。但是_变量仍然指代它。
➍ 调用wref()依旧返回{0, 1}。
➎ 计算这个表达式时,{0, 1}存在,因此wref()不是None。但是,随后_绑定到结果值False。现在{0, 1}没有强引用了。
➏ 因为{0, 1}对象不存在了,所以wref()返回None。

weakref.ref类其实是低层接口,供高级用途使用,多数程序最好使用weakref集合和finalize。也就是说,应该使用WeakKeyDictionary、WeakValueDictionary、WeakSet和finalize(在内部使用弱引用),不要自己动手创建并处理weakref.ref实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值