python垃圾回收机制

最近有些空余时间,看了看python方面的书,在这里进行一下自我总结

其实我们都知道,python在运行过程中会产生很多变量,这些变量都是存储在内存中的,但是变量后续会越来越多,导致占满内存,然后程序就会异常终止,所以针对这些,python有自己的一套垃圾回收机制,解决办法有三种。

1、引用计数
在python中,每一个对象的生命周期绝大部分通过对象的引用计数来管理,每当对象被创建或者被引用的时候就会将该对象的引用计数加一,当对象的引用被销毁时该对象的引用次数减一,当引用计数为0时,表示程序中已经没有任何对象持有该对象的引用,即程序中不会再使用到这个对象,所以其所占有的空间也就可以被释放了

那么什么时候对象的引用次数会增加呢?
(1)、对象被创建
(2)、对象被引用
(3)、对象作为参数被传递到函数内部
(4)、对象作为一个元素添加到容器中

同理,对象的引用次数减一的情况也有四种。
(1)、对象的别名被显式销毁
(2)、对象的别名被赋予新的对象
(3)、对象离开它的作用域(函数局部变量)
(4)、从容器中删除对象,或者容器被销毁

2、标记清除
程序运行过程中一定会有交叉引用的问题存在,导致每个对象的引用计数不为零,即A赋值B,B赋值A,这样就造成了其所占用的内存空间永远都不会被回收的局面,这个缺点是致命的
为了解决这样的问题,python引入了标记清除法和分代回收算法

标记清除算法是一种基于对象可达性分析的回收算法,该算法分为两个步骤,分别是标记和清除,标记阶段,将所有活动对象进行标记,清除阶段将所有未进行标记的对象进行回收即可,那么又是如何判断哪些对象是活动对象呢?

从根节点出发,与根节点直接相连或者间接相连的对象,我们将其标记为活动对象,之后进行回收阶段,将未标记的对象进行清除,前面所说的根节点可以是全局变量或者调用栈

标记清除算法主要处理一些容器对象,该方法比较保险,可以做到不误杀不遗漏,但是GC必须要扫描整个堆内存,即使只有少量的非可达对象需要回收也需要扫描全部对象,这是一种巨大的性能浪费

3、分代回收

为了解决标记清除算法带来的性能损耗问题,python引入了分代回收的算法,将系统中存活时间不同的对象划分到不同的内存区域,共三代,新生成的对象是0代,经过一次垃圾回收后,还存活的对象会升级到1代,以此类推,2代中的对象是存活最久的对象

那么什么时候触发垃圾回收算法呢?
程序的不断运行导致不断创建新的对象,同时通过引用计数也会销毁大多对象,python会保持这些对象的跟踪,由于交叉引用的存在,以及存活了长时间的对象,这就造成新生的对象数量会大于被回收的对象的数量,一旦两者的差值达到某个的阈值,就会触发垃圾回收机制,使用标记清除将死亡对象进行清除,同时将存活的对象移动到1代,以此类推,当两者的差值再次达到阈值的时候又触发垃圾回收机制,将存活的对象移动到2代。

这样通过对不同代的阈值做不同的设置,就可以做到在不同代使用不同的时间间隔进行垃圾回收,以追求性能最大

除了上面所说的差值达到一定的阈值会触发垃圾回收之外,我们还可以显示的调用gc.collect()来触发垃圾回收,最后当程序退出时也会进行垃圾回收。

总结
python中的垃圾回收机制主要是这三种方法来解决,其中引用计数是最简单直接的,但是需要维护一个字段且针对交叉引用无能为力

标记清除算法主要是为了解决引用计数的交叉引用问题,该算法的缺点就是需要扫描整个堆的所有对象,性能消耗有点大

而分代回收算法的引入则解决了标记清除带来的性能问题,该方法也是建立在标记清除的基础之上的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值