python的垃圾回收机制

python的垃圾回收机制:应用计数为主,标记清除和分代回收为辅

一.引用计数

这里1这个对象并没有在内存中新建,因为python有代码块机制,在python解释器启动的时候会将-5~正无穷的数字加载到内存中等待调用,a=1只是为1添加了一个引用。

import sys
a = 1
print(sys.getrefcount(a))  #1366

再来看一个例子

a = 23345455               #引用次数1
b = a                      #2次
c = b                      #3次
print(sys.getrefcount(b))  #4 调用getrefcount()会再加一次,因此打印出来为4次
print(sys.getrefcount(c))  #4

得到结果为4,4.因为查看引用并非查看b或c对象被引用的次数,而是查看23345455这个值的被引用次数,此时删除c变量,23345455这个值的被引用次数-1,直到为0,就会被回收。

二.循环引用

通过引用计数器的方式基本上可以完成Python的垃圾回收,但它还是具有明显的缺陷,即:“循环引用” 

import gc
import objgraph
class Foo(object):
    def __init__(self):
        self.data = None
# 在内存创建两个对象,即:引用计数器值都是1
obj1 = Foo()
obj2 = Foo()
 
# 两个对象循环引用,导致内存中对象的应用+1,即:引用计数器值都是2
obj1.data = obj2  #将obj2赋值给obj1.data,obj2指向Foo(),因此Foo()的引用为2
obj2.data = obj1  #同上
 
# 删除变量,并将引用计数器-1。
del obj1
del obj2
 
# 关闭垃圾回收机制
gc.disable()
 
# 至此,由于循环引用导致内存中创建的obj1和obj2两个对象引用计数器不为0,无法被垃圾回收机制回收。
# 所以,内存中Foo类的对象就还显示有2个。
print(objgraph.count('Foo'))

循环引用的问题会引发内存中的对象一直无法释放,从而内存逐渐增大,最终导致内存泄露。

为了解决循环引用的问题,Python又在引用计数器的基础上引入了标记清除和分代回收的机制。

三.标记清除和分代回收

Python为了解决循环引用,每创建一个对象都会将对象放到一个双向链表中,每个对象中都有 _ob_next 和 _ob_prev 指针

 

1.当对象个数超过 700个 时,Python解释器就会进行垃圾回收,然后代码中主动执行 gc.collect() 命令时,Python解释器就会进行垃圾回收。

2.Python解释器在垃圾回收时,会遍历链表中的每个对象,如果存在循环引用,就将存在循环引用的对象的引用计数器 -1,同时Python解释器也会将计数器等于0(可回收)和不等于0(不可回收)的一分为二,把计数器等于0的所有对象进行回收,把计数器不为0的对象放到另外一个双向链表表(即:分代回收的下一代)

3.python里一共有三代,每个代的threshold值表示该代最多容纳对象的个数。默认情况下,当0代超过700,或1,2代超过10,垃圾回收机制将触发。

4.0代触发将清理所有三代,1代触发会清理1,2代,2代触发后只会清理自己。

参考:https://www.jianshu.com/p/1e375fb40506

posted @ 2019-10-18 20:09  MISF  阅读(65)  评论(0编辑  收藏  举报
     JS过度和变形效果演示   
  
    html5.png