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&)