python垃圾回收算法

标准python垃圾回收器由两部分组成,即引用计数回收器和分代垃圾回收器(即python包中的gc module)。其中,引用计数模块不能被禁用,而GC模块可以被禁用。

引用计数算法

python中每个变量都是对象,每个对象核心都包含一个结构体PyObject:

 typedef struct_object {
 int ob_refcnt;
 struct_typeobject *ob_type;
} PyObject;

其中ob_refcnt变量记录了这个对象被引用的数量,当这个对象的引用被赋值给另一个变量或者这个引用被删除(如del a)。那么ob_refcnt就会随之加1或者减1。引用计数增加的场景有:

  • 赋值操作
  • 参数传递
  • 添加object到list末尾

如果某个对象的引用计数为0,那么python会立马调用函数释放内存空间,此时可能导致这个对象引用的其他对象引用计数也为0,因此一个对象消亡可能引起一连串对象内存空间被释放。
一般说来,全局变量(定义在函数,类和代码块之外的变量)随python进程退出而释放,因此引用计数永远不会减为0。局部变量(定义在函数,类和代码块之内的变量)反之。
引用计数算法原理简单明了,但是存在循环引用,线程锁和内存性能开销等问题。

分代垃圾回收算法

引用计数算法最大问题就是循环引用,这种情况下循环引用的每个对象的引用计数最终都不会归零,如下图所示:
773612-20190324195711224-455040202.jpg
因此,python在gc module实现了循环检测算法来解决这个问题。循环引用只可能发生在容器对象之间,因此,GC循环检测也只对容器对象使用。对于只包含常量的容器(如包含常量的tuple),GC也会把这部分排除掉。
GC将容器对象分为3代,定期清理每代的垃圾对象。新分配的对象总是在第0代,如果经历过一次垃圾回收依然存活则移入下一代。新生代的回收频率比老年代高,大部分新对象很快就会释放,因此生命周期都只是停留在第0代。这种分代回收方式可以提高GC性能,减少停顿时间。

GC进行时需要停止程序的执行以免引用关系改变。

为了确定何时可以执行垃圾回收,GC每一代维护都会count和threshold两个变量,其中count=上一次垃圾回收后分配的新对象-上一次垃圾回收后已经消亡对象(因为引用计数为0而被释放),每次对象创建时候都会比较count和threshold大小,如果count>threshold,python就会启动垃圾回收进程。
以下详细说明CPython循环检测的原理,CPython维护两个双向链表:一个是需要检测的对象关系链表(objects list),一个是存放无法访达的对象链表(Unreachable list)。

  1. 如下图所示,假设现在清理的是第0代的垃圾对象。左边的需要扫描的对象列表中link4是一个循环引用。varA是link1的外部引用,可能是其他代的对象。每个对象除了有一个引用计数变量ref count外,还维护一个gc_ref变量,初始时ref count=gc_ref.
    773612-20190324195711226-1845995737.jpg
  2. GC遍历objects list每个对象,将这个对象所引用的其他对象的gc_ref减1。773612-20190324195711240-772144055.jpg
  3. GC将步骤2中gc_ref=0的对象挪到Unreachable list中,下图表示将已经处理的link3和link4移到Unreachable list,但是还没有处理link1和link2.773612-20190324195711245-1330867804.jpg
  4. 当GC扫描link1时候,发现gc_ref=1,是可以访达的,那么GC就会循环遍历link1引用的对象,将其标记为可以访达。因为link3经过此轮后标记为可以访达,那么就会将其从Unreachable list移到之前的list中。773612-20190324195711252-148977328.jpg
  5. GC扫描完所有的对象后,就会启动垃圾回收进程,将Unreachable list中的对象清理掉。

为了性能考虑,我们应该尽量避免循环引用,可以使用weakrefmodule,weakref.ref不会增加对象的引用计数并且对象被回收后返回None。此外,可以使用gc.disable()手动关闭GC垃圾回收,这在某些特殊情况下有帮助。

参考资料

[1] Garbage collection in Python: things you need to know
[2] Python垃圾回收机制
[3] The Garbage Collector
[4] Python垃圾回收(GC)三层心法,你了解到第几层

转载于:https://www.cnblogs.com/bo2256321/p/python-la-ji-hui-shou-suan-fa4.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值