Python的垃圾回收机制

Python的垃圾回收机制

引入计数器为主,标记清除和分代回收为辅

1.引入计数器

环状双向链表refchain

在python程序中创建的任何对象都会放在refchain链表中

当python程序运行时,会根据数据类型的不同找到其对应的结构体,根据结构体中的字段来进行创建相关的数据,然后将对象添加到rechain双向链表中

在C源码中有两个关键的结构体:PyObject,PyVarObject

每个对象中有ob_refcent就是引用计数器,默认值为1,当其他变量引用对象时,引用计数器就会发生变化。

# 引用
a = 999
b = a   # 相当于ob_refcent为2
​
del b   # b变量删除:b对应对象计数器的引用-1
​
#当一个对象的引用计数器为0时,意味着没有人在使用这个对象了,这个对象就是垃圾,进行垃圾回收
#回收:1对象从rechain链表移除。2:将对象销毁,内存归还。
​

只用计数器会出现bug 循环引用&&交叉感染

会导致变量永远都在内存中,无法清除

2.标记清除

目的:为了解决引用计数器循环引用的不足

实现:在python的底层再去维护一个链表。这个链表专门放那些可能存在循环引用的对象(list/dict/tuple/set)。 # 元素中还有可能再放其他元素的

在python内部,某种情况下触发,回去扫描可能存在循环引用的链表中的每一个元素,检查是否有循环引用,如果有让双方的引用计数器-1;如果是0则垃圾回收。

问题:

什么时候扫描?

可能存在循环引用的链表扫描的代大。要扫描每一个元素,耗时久

3.分代回收

将可能存在循环引用的对象维护成3个链表:(在refchain中检测到可循环对象就放入0代)

0代:0代中的对象个数达到700个则扫描一次。(扫描,将引用计数器-1如果不等于0,则将对方升级放入1代)

1代:0代如果扫描十次则一代扫描一次。()

2代:1代扫描十次则二代扫描一次。

4.小结

在python中维护了一个叫refchain的双向链表,这个链表存储创建了所有的对象,每种类型的对象中都有一个ob_refcnt引用计数器的值,引用的个数进行+1,-1,最后当引用计数器变为0时进行垃圾回收(对象销毁,refchain中移除)。

但是在python中对于可以有多个元素组成的对象可能会存在循环引用的问题,为了解决这个问题python又引入了标记清除和分代回收,在其内部为4个链表,

refchain 0代 1代 2代

在源码内部达到各自的阈值时,就会触发扫描链表进行标记清除的动作(有循环则各自-1)。

5.Python缓冲池

5.1池(int)

对于整数对象,解释器会对常用的小整数进行缓存,这样可以提高性能和节省内存。具体而言,对于范围在 -5256 之间的整数,Python会缓存这些对象,使得同一值的整数对象共享同一个内存地址。这种优化是为了减少频繁使用的小整数对象的创建和销毁开销。

5.2 free_list(float/list/tuple/dict)

当一个对象的引用计数器为0时,理应进行回收,实际不会回收,而是放到free_list的链表中当缓存。以后再去创建对象时,不再重新开辟内存,而是直接使用free_list。

v1 = 3.14  # 开辟内存,内存存储结构体中定义的那几个值,并且保存到refchain中。
del v1  # refchain中移除,将对象添加到free_list中(比如存80个浮点类型数),free_list满了则销毁
v9 = 9999.99  # 不会重新开辟内存,直接去free_list中获取对象,将对象内部数据初始化,再放到refchain中
  • 30
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值