python-垃圾回收
python的垃圾回收用的是引用计数、标记清除、代际回收三个方法。
引用计数
引用计数,维护一个值来记录对象被引用次数,当引用次数为0时,回收这个对象的内存。
当对象被创建,被其他变量引用a=b、被传递为函数参数、作为列表元组等容器里的元素时引用加一。
当指向对象的变量被显示的销毁del a,变量指向其他对象a=2,局部变量被销毁、引用对象的容器被销毁,从容器中删除时引用减一。
引用计数的问题
-
循环引用,循环引用的对象的引用计数不会变为0,所以不会被回收。
-
每次进行垃圾回收需要遍历所有对象,而有很多对象的声明周期很长,造成资源浪费。
标记清除
标记清楚法用来解决循环引用问题。
循环引用实际上只会发生在container对象(内部可持有其他对象引用的容器类的数据对象和自定义对象)上。
从寻根对象集合root object(全局引用和函数栈的引用,根对象就是全局变量、调用栈、寄存器。这些对象不可被删除)出发,对root object集合中的每一个引用进行探索,能达到的对象标记为不可删除(垃圾检测阶段),当垃圾检测阶段结束,所有对象分为可达和不可达的,回收不可达对象。
图片来源公众号古明地觉的python小屋,博客园:古明地盆https://www.cnblogs.com/traditional/
他的博客内容质量很高,建议直接看他的博客
分代回收
分代回收就是用来解决每次垃圾回收需要遍历全部对象的问题。很多对象的生命周期很长,经过的垃圾回收次数越多,生命周期就越长。
利用空间换时间,维护三个链表,分别为第0代,第1代,第2代。新建立的对象会被加入到第0代列表中,经过一次垃圾回收,剩下的对象会被加入到第1代,第一代经过垃圾回收后剩下的对象会被加入到第2代。
图片来源公众号古明地觉的python小屋,博客园:古明地盆https://www.cnblogs.com/traditional/
1.当第0代链表中的container对象(可持有其他对象引用的对象)数量即count超过700时,对第0代进行垃圾回收,剩余对象加入第1代,同时第一代链表的count+1
2. 当第0代链表清理次数达到11次时,第1代链表的count会超过阈值10,就会对第一代链表进行垃圾回收,然后把剩余对象加入第2代,同时第2代链表的count+1
3. 当第1代链表进行了11次垃圾回收时,第2的链表的count也会超过阈值10,然后对第2代链表进行垃圾回收。