?Python的垃圾回收机制
Python的GC模块主要运用了“引用计数”(reference counting)来跟踪和回收垃圾。在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用的问题,并且通过“分代回收”(generation collection)以空间换取时间的方式来进一步提高垃圾回收的效率。
解释器在执行到定义变量的语法时,会申请内存空间来存放变量的值,而内存的容量是有限的,这就涉及到变量值所占用内存空间的回收问题,当一个变量值没有用了(简称垃圾)就应该将其占用的内存给回收掉,那什么样的变量值是没有用的呢?
? 单从逻辑层面分析,我们定义变量将变量值存起来的目的是为了以后取出来使用,而取得变量值需要通过其绑定的直接引用(如x=10,10被x直接引用)或间接引用(如l=[x,],x=10,10被x直接引用,而被容器类型l间接引用),所以当一个变量值不再绑定任何引用时,我们就无法再访问到该变量值了,该变量值自然就是没有用的,就应该被当成一个垃圾回收。
? 毫无疑问,内存空间的申请与回收都是非常耗费精力的事情,而且存在很大的危险性,稍有不慎就有可能引发内存溢出问题,好在Cpython解释器提供了自动的垃圾回收机制来帮我们解决了这件事。
引用计数
引用计数:内存中的值被引用的次数,当计数为0时,该变量值就成为了垃圾,就会被回收。 下述情况计数会加1: 对象被创建 a=14 对象被引用 b=a 对象被作为参数,传到函数中 func(a) 对象作为一个元素,存储在容器(比如数组、列表、元组)中 List={a,“a”,“b”,2}
与上述情况相对应,当发生以下四种情况时,计数器-1 当该对象的别名被显式销毁时 del a 当该对象的引别名被赋予新的对象 a=26 一个对象离开它的作用域,例如 func函数执行完毕时,函数里面的局部变量的引用计数器就会减一(但是全局变量不会) 将该元素从容器中删除时,或者容器被销毁时。 ?
PyObject
- python里每一个东西都是对象,它们的核心就是一个结构体:PyObject
- PyObject是每个对象必有的内容,其中
ob_refcnt 就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt 就会增加,当引用它的对象被删除,它的ob_refcnt就会减少
引用计数优缺点
- 优点?
简单实时,一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时。 - 缺点?
维护引用计数消耗资源,会造成循环引用导致无法回收,造成内存泄露
循环应用
list1 = []
list2 = []
list1.append(list2)
list2.append(list1)
- list1与list2相互引用,如果不存在其他对象对它们的引用,list1与list2的引用计数也仍然为1,所占用的内存永远无法被回收,这将是致命的。
|