理解Python的GC垃圾回收机制,让你写出更好的代码

GC(Garbage Collection)的好处

GC(垃圾回收机制)毫无疑问是编程史上的一次革命,在没有垃圾回收机制的C/C++时代,经常造成内存泄漏(反正我C++是被内存泄漏玩哭了)而使程序员bug改到崩溃。所以当GC出现时,人们沸腾了,因为程序员再也不需要考虑内存泄漏的问题,可以好好关心业务代码了,这是多么可喜可贺的事啊。就像你家雇了个保姆,你现在可以专心做喜欢做的事,不用去打扫了一样,多么舒服啊。但如果你了解GC,你将写出更快速的代码,这就是为什么人们要垃圾分类,因为方便收垃圾的人处理。

 

python的垃圾回收机制

python是以引用计数为主,标记-清除与隔代回收为辅的垃圾回收机制。python很早就有了GC,甚至是最早提出引用计数的就是Guido提出的。

引用计数

为了不浪费内存资源,python使用引用计数来进行垃圾回收。比如,

str1 = "aaa"

就是先申请一块内存,写入"aaa",然后将str指向aaa所在的内存。并引用计数+1

如果是

str1 = "aaa"
str2 = str1

则会像这样,创建多一个引用指向字符串aaa的区域,此时引用计数变为2。引用不是再创建一个aaa。这样便节省了再次创建的开销。(其中数字[-5 ~ 256]这个区间里的数字,python虚拟机会提前申请好内存空间。因为命中率很高)

当你调用del时,便会删除引用。

由于Python比较爱干净,当引用计数为0时(即没有指向这块内存是),GC就会回收内存。(其他语言不会马上回收,单纯的python爱干净所以喜欢立刻回收)

 

一般来说,引用计数就够用了,又高效。但是,聪明的你估计很快发现了问题。

引用计数的问题

就像多线程会死锁一样,引用计数也会出现类似死锁的“互相引用”。比如下面的程序,创建C1跟C2,然后在C1里引用C2,在C2里引用C1。

再没执行del前是这样的

执行del后变成这样

你会发现,明明已经没有变量引用了,但这两个内存还是互相引用着,引用计数不为0,因此无法被GC释放。

因此,出现了解决变量互相引用的方法——零代

零代

零代是python源码里的称呼,是结合了标记-清除与隔代回收的算法,用来解决互相引用的问题。首先说说什么是标记清除。

 

标记清除

标记清除是ruby使用的,python后来学习后结合了一部分思想。

标记清除很简单,首先创建好一个链表,把他们连起来,默认标记为0。每当有变量申请内存时,给出一个节点,然后被引用的标记+1,没使用的标记为0。如下图

当分配满了之后,会GC会检查,此链表中的节点,如果标记为0的,则清除后回收,再将这些0的全部连接成一个新的链表,反复利用。而为大于0的则代表存活的。跟引用计数的区别是,一开始就申请好了内存

而python中,则使用的是有向图,可以直达的代表存活

在上图中,我们把小黑圈视为全局变量,从小黑圈出发,对象1可直达,那么它将被标记,对象2、3可间接到达也会被标记,而4和5不可达,那么1、2、3就是活动对象,4和5是非活动对象会被GC回收。

隔代回收

即把垃圾分成几代进行回收,比如java中有年轻代跟老年代。python中则分为3代,为0代,1代,2代。

为什么要分代?

答案,节省开销。这来源于计算机界的一个经验——弱代假说(weak generational hypothesis):年亲的对象通常死得也快,而老对象则很有可能存活更长的时间。因此,老年代的要很少去执行回收,可以节省开销。

 

解决变量互相引用

python使用零代解决变量互相引用。零代跟上面提到的标记-清除一样,使用链表连起来。

跟标记-清除一样,当0代到达一定个数时,会触发垃圾回收。(python源码中0代为700个触发,1代为10个触发,2代也为10个触发,没必要记数字,因为个数可能已经修改)

但它比标记清除多了一步来解决变量互相引用。即——计算有效引用。说起来其实很简单

每次引用,看看能不能走回去,如果可以,则代表互相引用,两个变量引用数各-1。

因此,上面的ABC跟DEF相互引用减掉之后,都变成0,如下图

然后此时,只剩下有效的引用计数。有效引用计数为0的,则执行垃圾回收,如果引用计数不为0,将升代,0代变到1代,1代变到2代

 

以上便是python的垃圾回收机制

参考文章

https://www.jianshu.com/p/1e375fb40506(若失效:https://app.yinxiang.com/Home.action#n=0f6f7c70-7f39-4bc2-985b-2d8db58e5fea&s=s64&ses=4&sh=2&sds=5&

http://www.wklken.me/posts/2015/09/29/python-source-gc.html(若失效:https://app.yinxiang.com/Home.action#n=9dbfb72c-d24f-49b9-af15-84bcf9712889&s=s64&ses=4&sh=2&sds=5&

https://sutune.me/2018/10/14/python-GC/(若失效:https://app.yinxiang.com/Home.action#n=df0fb321-0c24-41f4-b873-bd58dd24a1b8&s=s64&ses=4&sh=2&sds=5&

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值