Python垃圾回收

引用计数器为主,标记清除和分代回收为辅,+ 缓存机制

refchain

在Python中存在一个 环状双向链表 refchain,其存储着在Python中创建的所有对象

#define PyObject_HEAD PyObject ob_base;
#define PyObject_VAR_HEAD PyVarObject ob_base;
// 宏定义,包含 上⼀个、下⼀个,⽤于构造双向链表⽤。(放到refchain链表中时,要⽤到)
#define _PyObject_HEAD_EXTRA \
 	struct _object *_ob_next; \
 	struct _object *_ob_prev;

typedef struct _object {
 	_PyObject_HEAD_EXTRA // ⽤于构造双向链表
 	Py_ssize_t ob_refcnt; // 引⽤计数器
 	struct _typeobject *ob_type; // 数据类型
} PyObject;

typedef struct {
 	PyObject ob_base; // PyObject对象
	Py_ssize_t ob_size; /* Number of items in variable part,即:元素个数 */
} PyVarObject;

创建对象的两个关键的结构体:PyObject、PyVarObject

  • PyObject:包含了4个值,上一个对象_ob_next、下一个对象_ob_prev、引用个数ob_refcnt、类型ob_type
  • PyVarObject:由多个元素组成的对象除了以上4个值还包含 元素的个数 ob_size

引用计算器

refchain 中的所有对象内部都有⼀个 ob_refcnt ⽤来保存当前对象的引⽤计数器(即自己被引用的次数)
当引用计数器为0时,(无人使用)则为垃圾需要回收。
回收:

  1. 对象从 refchain 移除
  2. 将对象销毁,释放内存

标记清除

v1 = [11,22,33] # refchain中创建⼀个列表对象,由于v1=对象,所以列表引对象⽤计数器为1.
v2 = [44,55,66] # refchain中再创建⼀个列表对象,因v2=对象,所以列表对象引⽤计数器为1.
v1.append(v2) # 把v2追加到v1中,则v2对应的[44,55,66]对象的引⽤计数器加1,最终为2.
v2.append(v1) # 把v1追加到v1中,则v1对应的[11,22,33]对象的引⽤计数器加1,最终为2.
del v1 # 引⽤计数器-1
del v2 # 引⽤计数器-1

由于循环引⽤的问题,他们的引⽤计数器不为0(永远不会被销毁,内存一直被占)
标记清除:用一个链表,专门存放可能存在循环引用的对象(list、tuple、dict、set …)。在某种情况下,检查是否有循环引用,若有则双方的引用计数器-1。

分代回收

将可能存在循环引用的对象,拆分到3个链表(分别称为 0\1\2 代)
当链表达到阈值时,对应的链表进行扫描,除循环引用外,其余引用计数器各自-1
阈值

  • 0代:0代对象的数量
  • 1代:0代的扫描次数
  • 2代:1代的扫描次数

缓存机制

反复的创建和销毁会使程序的执⾏效率变低
python 在启动时会有一些池(数据池)用来存放一些常见的对象(需要时,直接从池中获取)
在这里插入图片描述
一个对象的引用计数器为 0 时,内存不会直接回收,而是会被添加到 free_list 中当缓存。
之后再去创建对象时,不再重新开辟内存,而是直接使用 free_list 将原本的对象初始化,再放到 refchain

小结

Python 垃圾回收机制综合运用引用计数、标记清除和分代回收策略并辅以缓存机制,既能及时回收无用对象,又能解决循环引用问题,还通过分代和缓存提升效率,保障程序内存管理的高效与稳定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值