垃圾回收机制

Python的GC模块

主要运用了“引用计数”(reference counting)来跟踪和回收垃圾。

在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用的问题。

通过“分代回收”(generation collection)以空间换取时间来进一步提高垃圾回收的效率。

(1)引用计数

当一个对象的引用被创建或者复制时,对象的引用计数加1;

当一个对象的引用被销毁时,对象的引用计数减1;

当对象的引用计数减少为0时,就意味着对象已经没有被任何人使用了,可以将其所占用的内存释放了。

优点:

实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时。

缺点:

执行效率低:维护引用计数消耗资源

循环引用:循环引用可以使一组对象的引用计数不为0,然而这些对象实际上并没有被任何外部对象所引用,它们之间只是相互引用。这意味着不会再有人使用这组对象,应该回收这组对象所占用的内存空间,然后由于相互引用的存在,每一个对象的引用计数都不为0,因此这些对象所占用的内存永远不会被释放。

(2)标记-清除

容器对象(比如:list,set,dict,class,instance)都可能产生循环引用。

不改动真实的引用计数,而是将集合中对象的引用计数复制一份副本,改动该对象引用的副本。对于副本做任何的改动,都不会影响到对象生命走起的维护。

这个计数副本的唯一作用是寻找root object集合(不能被回收的)。

寻找到root object集合之后,首先将内存链表一分为二,一条链表中维护root object集合,成为root链表,而另外一条链表中维护剩下的对象,成为unreachable链表。

现在的unreachable可能存在被root链表中的对象,直接或间接引用的对象,这些对象是不能被回收的,一旦在标记的过程中,发现这样的对象,就将其从unreachable链表中移到root链表中;

当完成标记后,unreachable链表中剩下的所有对象就是名副其实的垃圾对象了,接下来的垃圾回收只需限制在unreachable链表中即可。

缺点:当需要回收的内存块越多时,垃圾检测带来的额外操作就越多,而垃圾回收带来的额外操作就越少

(3)分代回收

当某些内存块M经过了3次垃圾收集的清洗之后还存活时,我们就将内存块M划到一个集合A中去,而新分配的内存都划分到集合B中去。

当垃圾收集开始工作时,大多数情况都只对集合B进行垃圾回收,然后才对集合A进进行,这就垃圾收集机制需要处理的内存少了,效率自然就提高了。

在这个过程中,集合B中的某些内存块由于存活时间长而会被转移到集合A中,当然,集合A中实际上也存在一些垃圾,这些垃圾的回收会因为这种分代的机制而被延迟。

posted on 2020-11-18 13:41  happygril3  阅读(112)  评论(0)    收藏  举报

导航