Python垃圾回收概述
Python中的垃圾回收机制基于引用计数(ob_refcnt),因此需要解决循环引用导致引用计数不能归零的问题。例如
|
|
虽然list1
与list2
已经成为需要回收的垃圾,但是由于相互引用导致引用计数不能归零,从而不能触发自动回收。因此Python引入了循环垃圾收集器
。
循环垃圾收集器的原理
判断对象是否为垃圾的逻辑比较直白,有外部引用或者被有外部引用的对象引用的对象为非垃圾对象;否则为垃圾对象。具体过程为,遍历所有对象将对象中引用的元素(其他对象)的引用计数减一,最后引用计数不归零的对象(存在外部引用)不是垃圾对象;被不是垃圾对象引用的元素(其他对象)也不是垃圾对象;剩余的则为垃圾对象。可以归纳为如下步骤:
- 创建可能存在循环应用的对象时,将该对象纳入链表进行管理
- 遍历所有纳入管理的对象,将对象引用的元素(其他对象)的引用计数减一
再次遍历:
<1> 处理对象:对该对象进行标记
所有引用计数为零的对象没有外部引用,标记为可能是垃圾;
所有引用计数不为零的对象存在外部引用,必然不是垃圾。1>|0 |可能是垃圾 |list1、list2、list3、list5|
|>0 |不是垃圾 |list4、list6|<2> 处理对象:遍历不是垃圾对象中的元素,不是垃圾对象中的元素必然不是垃圾2>
- 最后没有被确定不是垃圾的对象就是垃圾对象
这部分处理代码比较复杂,每个对象可能作为两种角色进行处理。作为代中的对象以及作为对象中的引用元素。如果作为元素被处理,则肯定不是垃圾。
各个阶段对象中的引用计数
垃圾对象不一定能被自动回收
垃圾对象不一定能被自动回收。所以上面的步骤只能确定垃圾对象,然后对垃圾对象进行额外处理甄别不能回收和能被回收的部分。
- 垃圾对象:没有外部引用的对象,也没有被有外部引用的对象引用
- 可回收对象:垃圾对象中能够被自动回收的对象
- reachable:非垃圾对象,存在外部引用或者被外部引用的对象引用
- unrechable: 垃圾对象
- collectable: 可回收对象
- finalizers: 垃圾对象中不能被自动回收的对象。一些对象存在析构函数并且相互引用,这样的对象Python不能自动确定回收顺序,因此不能被自动回收。
不是所有对象都纳入循环垃圾收集器
一些基本对象不会产生循环引用,例如int、float、string等,所以没有必须使用循环垃圾收集器,基本的引用计数回收机制即可。还有一些容器类对象,他们中的元素都是基本元素不会引起循环引用,例如{‘a’:1}、(1, 2, 3),因此也不纳入循环垃圾收集器。所以只有部分容器类对象、生成器、含__del__
类等才纳入循环垃圾收集器。
垃圾回收中的代
如上分析,整个循环垃圾收集的效率严重依赖可能引起循环引用的对象的个数。为了减少垃圾回收的动作,Python将对象分代:存活越长的对象越不可能是垃圾,就减少对其进行垃圾回收的次数。那么存活
的时间长短就用经过了几次垃圾回收来判断,于是刚创建的对象为一代,当经过一次垃圾回收还存活的对象放入二代;多次一代垃圾回收后,才进行一次二代垃圾回收。Python将整个对象分为三代,当分配足够数量的对象后(700)进行一次一代回收;当进行一定数量(10)一代回收后进行二代回收;同理进行三代回收。
gcmodule.c源码分析
|
|