一旦提到 垃圾回收机制就会关联到:引用计数器为主,标记清楚和分代回收为辅+缓存机制
但是一旦问到如何实现?
那么可能就不太好能回答清楚
1.引用计数器
1.1 环状双向链表refchian
python中创建的任何对象 都会放在refchain中
在C源码中如何体现每个对象都有相同的值:PYOBject结构体
封装了4个值:上一个对象、下一个对象、引用个数、数据类型
由多个元素组成的对象:PyObject结构体(4个值)+ob_size
1.2类型封装结构体
1.3引用计数器
回收:1、对象从refchain链表移除,2、将对象销毁、内存归还
引用技术器的bug:
循环引用的 问题:
循环引用和交叉感染
V1、V2应该是要被回收,但是引用计数器并非为0,所以就会出现循环引用的问题。
那么如何解决?
2、引入标记清除来解决
如何实现?
在python的底层再去维护一个链表,链表中专门存放哪些可能存在循环引用的对象(列表,字典,元组,集合)
比如:
第一个refchain不变,第二个链表存放可能会存在循环引用的对象,
在内部,某种情况下会扫描可能循环引用的列表中的每个元素,检查是否有循环引用,如果有,则让双方的计数器,各自减1,如果为0则垃圾回收。
问题:
什么时候扫描?
可能存在循环引用的链表扫描代价大,每次扫描耗时久
3、分代回收
将可能存在循环引用的对象维护成3个链表:
0代:0代中对象个数达到700个扫描一次,最开始的对象创建都会添加到0代里面去,直到0代达到了700以后,就会对他进行扫描,如果是循环引用就自减1,如过是垃圾就自动回收,如果不是垃圾就让他升级为1代。这样第一次扫描完,是垃圾就回收,不是就升级,并标记扫描一次了。这样循环了10次之后,才会扫描一代。
1代:0代扫描10次,则1代扫描1次
2代:1代扫描10,则二代扫描一次i
4、小结
首先在python中有维护了一个refchain的双向链表,这个链表中存储程序创建的所有对象,每种类型的对象中有一个ob_refcnt引用计数器的值,引用个数+1,-1,最后当引用计数器变为0的时候就会进行垃圾回收,要么是对象销毁,就是从refchain中移除。
但是对于python中的那些可以有多个元素组成的对象可能会存在循环引用的问题,为了解决这个问题,那么就引入了标记清楚和分代回收,在其内部维护了4个链表,refchain和0代1代和2代。
在源码的内部,当达到各自的阈值时候就会扫描链表进行标记清除的动作(有循环则各自减1)
但是在python的源码内部又提出了优化机制。
5、Python缓存
5.1池
在内部池内,计数器不可能为0.
5.2 free list机制(float/list/tuple/dict)
当引用计数器为0时,按理说应该回收,内部不会去回收,而是将对象添加到free_list链表中当缓存,以后再去创建对象时候,不再重新开辟内存,而是直接free_list