Python语法入门之垃圾回收机制
前言
解释器在执行到定义变量的语法时,会申请内存空间来存放变量的值,而内存的容量是有限的,这就涉及到变量值所占用内存空间的回收问题,当一个变量值没有用了(简称垃圾)就应该将其占用的内存给回收掉,那什么样的变量值是没有用的呢?
单从逻辑层面分析,我们定义变量将变量值存起来的目的是为了以后取出来使用,而取得变量值需要通过其绑定的直接引用(如x=10,10被x直接引用)或间接引用(如l=[x,],x=10,10被x直接引用,而被容器类型l间接引用),所以当一个变量值不再绑定任何引用时,我们就无法再访问到该变量值了,该变量值自然就是没有用的,就应该被当成一个垃圾回收。
毫无疑问,内存空间的申请与回收都是非常耗费精力的事情,而且存在很大的危险性,稍有不慎就有可能引发内存溢出问题,好在Cpython解释器提供了自动的垃圾回收机制来帮我们解决了这件事。
什么是垃圾回收机制?
垃圾回收机制(简称GC)是Python解释器自带一种机,专门用来回收不可用的变量值所占用的内存空间
为什么要用垃圾回收机制?
程序运行过程中会申请大量的内存空间,而对于一些无用的内存空间如果不及时清理的话会导致内存使用殆尽(内存溢出),导致程序崩溃,因此管理内存是一件重要且繁杂的事情,而python解释器自带的垃圾回收机制把程序员从繁杂的内存管理中解放出来。
垃圾回收机制原理分析
Python的GC模块主要运用了“引用计数”(reference counting)来跟踪和回收垃圾。在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用的问题,并且通过“分代回收”(generation collection)以空间换取时间的方式来进一步提高垃圾回收的效率。
引用计数
引用计数就是:变量值被变量名关联的次数
如果有新的引用指向对象,对象引用计数增加一,引用被销毁时,对象引用计数减去一,当用户的引用计数为0是 该内存被释放
# 例如
name = 'zz' # 变量值zz被关联了一个变量名name,称之为引用计数为1
m = name # 把name的内存地址给了m,此时,m,name都关联了zz,所以变量值zz的引用计数为2
name = 'qq' # 名字name先与值zz解除关联,再与qq建立了关联,变量值zz的引用计数为1
del m # del的意思是解除变量名m与变量值zz的关联关系,此时,变量zz的引用计数为0
# 值zz的引用计数一旦变为0,其占用的内存地址就应该被解释器的垃圾回收机制回收
变量值被关联次数的增加或减少,都会引发引用计数机制的执行(增加或减少值的引用计数),这存在明显的效率问题。
引用计数机制还存在着一个致命的弱点,即循环引用(也称交叉引用)
循环引用会导致:值不再被任何名字关联,但是值的引用计数并不会为0,应该被回收但不能被回收
标记清除
# 首先标记对象(垃圾检测),然后清除垃圾(垃圾回收)
首先初始所有对象标记为白色,并确定根节点对象(这些对象是不会被删除),标记他们为黑色(表示对象有效)。
将有效对象引用的对象标记为灰色(表示对象可达,但它们所引用的对象还没检查),检查完灰色对象引用的对象后,将灰色标记为黑色。
重复知道不存在灰色节点为止。
最后白色节点都是需要清除的对象
分代回收
# 垃圾回收器会更频繁的处理新对象。
一个新的对象即是你的程序刚刚创建的,而一个老的对象则是经过了几个时间周期之后仍然存在的对象。
Python会在当一个对象从零代移动到一代,或是从一代移动到二代的过程中提升(promote)这个对象