引言
垃圾是我们在写代码的时候,经常对某些变量不管,从而导致内存占用就会越来越多。
解释器在执行到定义变量的语法时,会申请内存空间来存放变量的值,而内存的容量是有限的,这就涉及到变量值所占用内存空间的回收问题。
当一个变量值没有用了(简称垃圾)就应该将其占用的内存给回收掉。单从逻辑层面分析,我们定义变量将变量值存起来的目的是为了以后取出来使用,而取得变量值需要通过其绑定的直接引用(如x=10,10被x直接引用)或间接引用(如A=[x,],x=10,10被x直接引用,而被容器A类型间接引用)。所以当一个变量值不再绑定任何引用时,我们就无法再访问到该变量值了,该变量值自然就是没有用的,就应该被当成一个垃圾回收。
毫无疑问,内存空间的申请与回收都是非常耗费精力的事情,而且存在很大的危险性,稍有不慎就有可能引发内存溢出问题,好在Cpython解释器提供了自动的垃圾回收机制来帮我们解决了这件事。
什么是垃圾回收机制?
● 垃圾回收机制(简称GC)是Python解释器自带的一种机制;
● 专门用来回收不可用的变量值所占用的内存空间(在内存中,没有变量名指向的数据都是垃圾数据)。
为什么要有垃圾回收机制?
● 程序运行过程中会申请大量的内存空间,而对于一些无用的内存空间如果不及时清理的话会导致内存使用殆尽(内存溢出),导致程序崩溃,因此管理内存是一
垃圾回收机制原理
● 引用计数为主,分代回收、标记清除为辅。
● Python的GC模块主要运用了“引用计数”(reference counting)来跟踪和回收垃圾。
● 在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用的问题,并且通过“分代回收”(generation collection)以空间换取时间的方式来进一步提高垃圾回收的效率。
(1)引用计数
num = 1 # 变量值1的引用次数就是1age = num = 1 # 变量值1的引用次数就是2age = num = 2 # 变量值1的引用次数就是0age = 1 # 变量值1的引用次数就是1
(2)标记清除
内存在每一次运行的时候都会扫描一遍内存,第一次扫描,发现 1 挂了,变成了垃圾,不会立即清除,因为可能在某块代码又对 1 进行了引用,而是在发现是垃圾后给这个垃圾打上一个标签,这个垃圾已经出现一次了。第二次扫描,发现 1 挂了,变成了垃圾,在发现是垃圾后给这个垃圾打上一个标签,这个垃圾已经出现二次了,当这个垃圾出现 10 次,则提一下权重。
(3)分代回收
每一次扫描都会发现垃圾,垃圾未必是当前必须清除掉的垃圾,所以打上标签。
①新生代 : 隔 10 min 扫描一次,一直发现有一个垃圾存在,当他的标记次数达到 100 次的时候就给他提权到青春代;
②青春代 : 隔 20 min 扫描一次 ,一直发现有一个垃圾存在,当他的标记次数达到 200 次的时候就给他提权到老年代;
③老年代 : 隔 30 min 扫描一次 ,一直发现有一个垃圾存在,当他的标记次数达到 300 次的时候就给他清除。
不断提权的原因是,垃圾可能会被捡起来重新使用,为了避免重复开销内存,于是就有了上面的机制。
小整数池概念
python中经常使用的一些数值定义为小整数池,小整数池的范围是[-5,256],python对这些数值已经提前创建好了内存空间。即使多次重新定义也不会再重新开辟新的空间,但是小整数池外的数值在重新定义时都会再次开辟新的空间。
所以对于小整数池中的数,内存地址一定是相同的,小整数池中外的数,内存地址是不同的。