Python垃圾回收机制
Python的垃圾回收机制是主要依靠GC(garbage collector)模块的引用计数来实现的。但是GC模块也有它的不足,下来我们来分别介绍下Python的几种垃圾回收机制。
GC模块之引用计数
原理
Python中变量的本质是对内存中某一块内存的引用。Python为每一个引用都维护了一个引用计数的属性。当一个引用被创建或者被复制时,就给相关对象的引用计数+1;相反当一个引用被销毁时就把相关对象的引用计数-1。当引用计数为0时,Python就会释放这个对象多占据的内存空间。
引用计数在每次引用的创建或者销毁时,都要做一次引用计数改变的操作,当引用创建或者销毁频繁时,就会导致效率降低。但是这样做带来的好处就是实时性。能够动态的、及时的管理内存。
其中还存在一个问题,当两个对象相互引用时,包含自己本身时,就会造成一个循环引用,导致不分内存永远无法被回收,导致内存泄漏。为了解决这个问题,就引入了标记-清楚机制和分代回收机制。
标记-清除回收机制
原理
当外界没用引用这两个对象时,这两个对象的引用计数都为1,如果识别出这两个属于循环引用的话,就减掉1,这样就可以看了真是的引用数量。
基于上一种思想,现在又对象A、B,从对象A出发,沿着引用找到对象B,把B对象的引用计数减1;然后从对象B出发,沿着引用找到对象A,把A对象的引用计数减1,这样就去掉了循环引用的关系。
但是这样做呢有一个不严谨的地方,就是如果对象A对对象B是单向引用的话,在到达对象B之前不知道引用了对象A,这样先给对象B的引用计数减1的话,就会导致对象B称为不可达的对象。
为了解决这个问题,Python的做法是将内存一分为二,内存C、D,将内存C用来保存真的引用计数,内存D用来做引用计数的副本,然后在这个副本数据上做实验。内存D中维护两张表E、F,表E用来保存不可回收的对象,表F保存可被回收的对象,也就是引用计数为0的对象。然后再从表F中找到那些被表E中对象直接或者间接单向引用的对象,把这些移动到表E中,这样就可以实现让不应该被回收的对象不被回收,应该被回收的对象都被回收了。
但是这样做的缺点就是效率不高。
分代回收机制
分代回收的目的是是为了提升垃圾回收的效率。
原理
将系统中的所有内存块根据其存活时间划分为不同的集合,每一个集合就成为一个“代”,Python默认定义了三代对象集合,垃圾收集的频率随着“代”的存活时间的增大而减小,第一代垃圾收集频率最高,第三代垃圾收集频率最低。也就是说,活得越长的对象,就越不可能是垃圾,就应该减少对它的垃圾收集频率。那么如何来衡量这个存活时间:通常是利用几次垃圾收集动作来衡量,如果一个对象经过的垃圾收集次数越多,可以得出:该对象存活时间就越长。
通常100次为一代。每一个对象都会先进入第一代的集合,当某个对象经历的100次垃圾回收以后依然存活,则进入第二代,在经历100次垃圾回收检测进入第三代。
参考文章
https://www.cnblogs.com/franknihao/p/7326849.html