16.python中的回收机制

python中的垃圾回收机制是以引用计数器为主,标记清除和分代回收为辅的 + 缓存机制
1.引用计数器在python内部维护了一个名为refchain的环状双向链表,在python中创建的任何对象都会放在refchain中

16.python中的回收机制

文章插图
name = "kunmzhao"age=18在python中创建的对象 , 在底层是由C语言中的结构体存储的
16.python中的回收机制

文章插图

16.python中的回收机制

文章插图
在这些结构体中存储这上一个对象 , 下一个对象 , 对象类型和引用个数
1.1 引用计数在python运行过程中,当我们创建一个对象的时候,会根据数据类型找到对应的结构体,创建对象 , 然后将对象添加在refchain中,并且引用计数为1.当对象被引用的时候就会+1,当对象被del的时候就-1
当一个对象的引用计数=0的时候 , 代表着这个对象就是垃圾,需要被回收,将对象从refchain中移除
1.2 循环引用问题当两个列表互相嵌套的时候,就出现了循环引用 , 不解决的话就出现了内存泄漏
16.python中的回收机制

文章插图
2.标记清除标记清除的目的是为了解决引用计数中的循环引用问题
实现原理:在python内部再维护一个双线链表,用于存放可能存在循环引用的对象(列表,字典,元组,集合类型),在一定条件下出触发链表的全部扫描,检查是否有循环引用,如果存在,则将双方的引用计数-1,如果为0则进行垃圾及回收
16.python中的回收机制

文章插图
3.分代回收目的是为了优化标记清除 , 因为如果标记清除维护的链表很大,每次都遍历会非常消耗性能,为此分代回收维护了3个链表,3个链表代表着不同的扫描阈值,当达到阈值之后才会触发对应链表的扫描
  • 0代:0代中对象的个数达到700个则扫描一次
  • 1代:0代扫描10次,则1代扫描一次
  • 2代:1代扫描10次,则2代扫描一次
将可能存在循环引用的对象放在0代的链表中,当0代中的对象个数超过700个就会触发一次链表扫描,将引用个数为0的回收,不为0的提升到1代链表中,并将0代扫描次数设置为1,当0代扫描次数为10次的时,就会触发1代进行扫描,将引用个数为0的进行回收,不为0的提升为2代 , 并将1代扫描次数设置为1
小结:在python中,维护了一个refchain的双向链表,存放着python中创建的所有对象,每个对象都有一个ob_refcnt的引用计数器,变量被引用一次,则个数+1,删除一次,个数-1,当个数为0 , 则进行垃圾回收,但是由于循环引用的问题 , python引入了标记清除和分代回收,又维护了3个链表,0代,1代和2代,代表着不同的阈值,当各自达到对应的阈值就会触发扫描链表 , 进行标记清除
4.缓存机制频繁的申请和销毁内存是非常消耗时间的,为此又引入了缓存机制,包括缓存池和free_list
4.1缓存池
池的做法是预先缓存一些常见的对象比如-5到256的整型对象,和ASCII字符表等 。当程序中定义了一个小的整型对象时,不需要从内存中申请内存,直接从池中获取即可
4.2 free_list
free_list的做法是将程序本来删除的对象 , 没有直接销毁而是放在一个名为free_list的数组中 。后面当程序中重新创建一个相同类型的对象时,不必新开辟空间而是直接从free_list中获取对象,重新进行初始化并放入到refchain中去 。
class Foo(object):name = 'kunmzhao'def __init__(self, name):self.name = namedef send_msg(self):print(self.name)foo = Foo('kunmzhao')# 2324775989200print(id(foo))del foofoo1 = Foo('Victor')# 2324775989200print(id(foo1))【16.python中的回收机制】

    推荐阅读