如题,Python中GC的垃圾回收算法是什么?
回答
Bravian回答
在Python中对象的释放有两种方法,引用计数法,垃圾回收法,这里主要讲解GC的垃圾回收方法。
GC的垃圾回收算法也有两种,标记-清除算法(mark-sweep)和分代(generational)算法。
标记清除法
通过标记清除法可以找到那些不可达的循环引用对象。在Python中,所有能够引用其他对象的对象都被称为容器(container),只有容器之间才可能形成循环引用。Python的垃圾回收机制利用了这个特点来寻找需要被释放的不可达的循环引用对象。
为了记录下所有的容器对象,Python将每一个容器都链到了一个双向链表中,使用双向链表是为了方便快速的在容器集合中插入和删除对象。有了这个维护了所有容器对象的双向链表以后,Python在垃圾回收时使用如下步骤来寻找需要释放的对象:
- 对于每一个容器对象,设置一个
gc_refs
值, 并将其初始化为该对象的引用计数值。 - 对于每一个容器对象,找到其引用的所有对象,将被引用对象的
gc_refs
值减1。 - 执行完步骤2以后所有
gc_refs
值还大于0的对象都被非容器对象引用着, 至少存在一个非循环引用。因此不能释放这些对象,将他们放入另一个集合。 - 在步骤3中不能被释放的对象, 如果他们引用着某个对象, 被引用的对象也是不能被释放的, 因此将这些对象也放入另一个集合中。
- 此时还剩下的对象都是无法到达的对象,现在可以释放这些对象了。
分代法
Python还将所有对象根据’生存时间’分为3代,从0到2。所有新创建的对象都分配为第0代。当这些对象经过一次垃圾回收仍然存在则会被放入第1代中。如果第1代中的对象在一次垃圾回收之后仍然存货则被放入第2代。对于不同代的对象Python的回收的频率也不一样。可以通过gc.set_threshold(threshold0[, threshold1[, threshold2]])
来定义。当Python的垃圾回收器中新增的对象数量减去删除的对象数量大于threshold0时,Python会对第0代对象执行一次垃圾回收。每当第0代被检查的次数超过了threshold1时,第1代对象就会被执行一次垃圾回收。当第1代被检查的次数超过了threshold2时,第2代对象也会被执行一次垃圾回收。threshold0,threshold1,threshold2的意义并不相同。
为什么要分代呢,这个算法的根源来自于weak generational hypothesis。这个假说由两个观点构成:
- 年亲的对象通常死得也快,比如大量的对象都存在于local作用域;
- 老对象则很有可能存活更长的时间,比如全局对象,module, class。
垃圾回收的原理就如上面提示,详细的可以看Python源码,只不过事实上垃圾回收器还要考虑__del__,弱引用等情况,会略微复杂一些。
触发垃圾回收的时机
有三种情况:
(1)达到了垃圾回收的阈值,Python虚拟机自动执行
(2)手动调用gc.collect()
(3)Python虚拟机退出的时候
(8)