美文网首页
Python垃圾回收和弱引用

Python垃圾回收和弱引用

作者: 萌萌哒的小叽叽丶 | 来源:发表于2018-12-25 19:27 被阅读0次

垃圾回收

  1. 引用计数 :CPython 中的主要垃圾回收算法,每个对象都会统计有多少引用指向自己;当引用计数归零时,对象立即销毁。
  2. 分代垃圾回收 :CPython 2.0 增加的新的算法,用于检测引用循环中涉及的对象组

即将销毁实例时,解释器会调用 __del__ 方法,给实例最后的机会,释放外部资源,但它不会销毁实例。

del

del 语句删除的是名称,而不是对象。但是在两种情况下可能会导致对象被回收:

  1. 删除的变量保存的是对象的最后一个引用 (引用计数)
  2. 删除变量后无法得到对象,如两个对象互相引用 (分代垃圾回收)

sys.getrefcount方法可以监控对象的引用计数,因为该方法调用本身也会增加对象的引用计数,所以结果会比实际想的要多1

''' 使用 weakref.finalize 注册回调函数,监视对象生命周期 '''
import weakref, sys

s1 = {1, 2 ,3}
s2 = s1

print(sys.getrefcount(s1))

def bye():
    print('Gone with the wind ... ')

# 注册回调函数 bye,当 s1 指向的对象被销毁,执行 bye 函数
ender = weakref.finalize(s1, bye)

ender.alive
3
True
# del 只是删除 s1 这个名称,但是它指向的对象还有 s2 作为引用
del s1
print(sys.getrefcount(s2))
ender.alive
2
True
# s2 被重新绑定,导致 {1, 2, 3} 无法获取,即引用计数归零,从而对象被销毁,bye函数回调
s2 = 'byebye'
ender.alive
Gone with the wind ... 
False

弱引用

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

weakref.ref 类的实例获取所指对象,提供的是底层接口,尽量不要手动创建并处理weakref.ref实例。
以下仅是演示弱引用 ...

# 创建弱引用对象
a_set = {0, 1}
wref = weakref.ref(a_set)
wref
<weakref at 0x03B7AA80; to 'set' at 0x03ACD3F0>
#返回被引用的对象,因为这里是控制台会话,返回的值(即[Out])会绑定到 _ 变量
wref()
{0, 1}
# 重新绑定 a_set,减少了 {0, 1} 的引用计数,但是 _ 变量仍然指向它
a_set = {2, 3}
wref()
{0, 1}
# 接下来的 [Out] 值会重新绑定 _ 变量,导致 {0, 1} 引用计数归零(ipython内核中还有__和___变量)
wref() is None
False
# 此时 _ 变量绑定的是 False,{0, 1} 引用计数归零(在Python原生控制台里是这样,但是这里的控制台的ipython内核,结果不一样)
wref() is None
False
# 在ipython内核中,使用 dir() 可以看到一些全局变量,globals可以看到他们的值,{0, 1}还有被 _5, _6 变量引用(即对应的[Out]值,具体视情况而定,这里就是 5 和 6),
# 除此之外,在 Out 以及 _oh 全局变量中,它们是保存当前所有[Out]值的字典(是同一个字典对象),5,6 key对应的value还是{0, 1}的引用,
# 最后,还有一个大坑,在ipython内核中,有_、__、___三个变量,分别表示当前Out值、上一个Out值、上上个Out值,所以到这个地方为止,___还是{0, 1}的引用
# 本以为这样就OK了,但是{0, 1}的引用还存在,已经想方设法绞尽脑汁在找,就是找不到是谁还在引用{0, 1},但至少弱引用不是;力竭,但愿以后能够发现
print(_5, _6, _oh[5], _oh[6])
print(_, __, ___)
_5, _6 = None, None
_oh[5], _oh[6] = None, None
___ = None
wref() is None
{0, 1} {0, 1} {0, 1} {0, 1}
False False {0, 1}
False

一般不要直接创建处理 weakref.ref 实例,最后使用 weakref 集合和 finalize,即 WeakKeyDictionaryWeakValueDictionaryWeakSetfinalize

WeakValueDictionary

WeakValueDictionary 类实现的是一种可变映射,值是对象的弱引用,被引用的对象被回收后,对应的键会主动删除,常用于缓存。
WeakKeyDictionary与之对应,它存储的键是对象的弱引用。

class Cheese:
    
    def __init__(self, kind):
        self.kind = kind
        
    def __repr__(self):
        return 'Cheese(%r)' % self.kind
stock = weakref.WeakValueDictionary()
catalog = [Cheese('A'), Cheese('B'), Cheese('C'), Cheese('D')]

for cheese in catalog:
    stock[cheese.kind] = cheese
sorted(stock.keys())
['A', 'B', 'C', 'D']
# 删除了 catalog 列表,对应的值弱引用字典中对应的键被删除,但是 'D' 还存在一个引用,for循环中的 cheese,它是全局变量
del catalog
sorted(stock.keys())
['D']
# 删除了 cheese 之后,所有键被删除
del cheese
sorted(stock.keys())
[]

md效果不好,原先是 jupyter notebook 版本

相关文章

  • Python垃圾回收和弱引用

    垃圾回收 引用计数 :CPython 中的主要垃圾回收算法,每个对象都会统计有多少引用指向自己;当引用计数归零时,...

  • Python 弱引用 学习

    转:python 初步认识弱引用 & 垃圾回收 - 要不,单步调试走起? - CSDN博客

  • java 弱引用

    强引用:不仅能引用到对象,而且告诉垃圾回收器不能回收; 软引用:引用到对象,内存不足时垃圾回收器可以回收; 弱引用...

  • Python del 和垃圾回收、弱引用

    del命令删除的是对象的引用。当删除的是对象的最后一个引用或无法得到对象时(只存在于两个对象之间的相互引用时,gc...

  • python的GC

    python垃圾回收机制 Python GC 主要是引用计数来跟踪和回收垃圾。 在引用技数的基础上, 通过"标记-...

  • Day11-Python垃圾回收机制笔记

    Python中的垃圾回收是以引用计数为主,标记清除和分代回收为辅。 【引用计数】 Python默认的垃圾收集机制是...

  • lua-弱表

    弱表是是具有弱引用的表,如果只有弱引用,垃圾收集器会回收这些对象。弱表可以有弱键或者弱值,如果具有弱键,垃圾回收器...

  • Python 垃圾回收学习

    垃圾回收机制一般有两个阶段:垃圾检测和垃圾回收。Python GC 主要使用引用计数来跟踪和垃圾回收。在引用计数的...

  • python面试题(五)

    1、简述python引用计数机制(联想到垃圾回收机制)python垃圾回收主要以引用计数为主,标记-清除和分代清除...

  • 引用类型

    参考博客:参考博客 类型: 强引用: 垃圾回收器不会回收 软饮用: 垃圾回收器在内存不够用的时候回收, 弱引用: ...

网友评论

      本文标题:Python垃圾回收和弱引用

      本文链接:https://www.haomeiwen.com/subject/cnkqlqtx.html