Python垃圾回收和弱引用

垃圾回收

  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 版本

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容