对象
双向循环链表
引用计数器
循环引用
标记清楚
可能存在循环引用的数据类型list/tuple/dic/set
另一个双向环状链表
什么时候扫描?扫描代价大
分代回收:0代、1代、2代
在python中维护了一个refchain的双向环状链表,这个链表中存储程序创建的所有对象,每种类型的对象中都有一个ob_refcnt引用计数器的值,引用个数+1、-1,最后当引用计数器变为0时会进行垃圾回收(refchain中移除、对象销毁)。
但是,在python中对于那些可以有多个元素组成的对象可能会存在循环引用的问题,为了解决这个问题python又引入了标记清除和分代回收,在其内部维护了4个链表。
- refchain
- 0代,700个对象
- 1代,0代扫描10次
- 2代,1代扫描10次
在源码内部当达到各自的阈值时,就会触发扫描链表进行标记清除的动作(有循环则各自-1)。
源码内部在上述的流程中提出了优化机制。
python缓存:
池(int),为了避免重复创建和销毁一些常见对象,维护池。
# 启动解释器时,python内部帮助我们创建:-5、-4、···、257
v1 = 7 # 内部不会开辟内存,直接去池中获取
v2 = 9 # 内部不会开辟内存,直接去池中获取
v3 = 9 # 内部不会开辟内存,直接去池中获取
print(id(v2)==id(v3))
v4 = 999
v5 = 666
free_list (float/list/tuple/dict)
当一个对象的引用计数器为0时,按理说应该回收,内部不会直接回收,而是将对象添加到free_list链表中当缓存。以后再去创建对象时,不再重新开辟内存,而是直接使用free_list
v1 = 3.14 # 开辟内存,内部存储结构体中定义那几个值,并存到refchain中。
del v1 # refchain中移除,将对象添加到free_list中(80个),free_list满了则销毁
v = 9.999 # 不会重新开辟内存,去free_list中获取对象,对象内部数据初始化,再放到refchain中