引子:当某值无法被访问到时,为了释放其所占的内存空间,将其从内存中消除,此为垃圾回收机制。
一、引用记数
1、定义:一个值只对应一个内存地址,但是可以被多个变量名所指向,每有一个这样的变量名,称为该值有一个引用计数。
2、直接引用:值直接被赋值绑定给变量名时,此为直接引用。
a = 10 # 值10直接赋值给a,此为直接引用
b = a # 将a与值10的绑定关系复制给b,而后b也直接指向值10的内存地址,此也为直接引用
3、间接引用:列表或字典等多个值组成的集和类型,本身是指向了其集和内的每个元素所对应的内存地址生成的目录的内存地址,再由目录中的每条单独的标记再指向元素本身的内存地址,此为间接引用。
x=10 #x直接引用了值10的地址
l=['a','b',x] # l=['a'的内存地址标记,'b'的内存地址标记,10的内存地址标记]
print(l[1]) # 由l[1]获得列表第二个元素的内存地址标记,再通过标记指向该内存地址
4、引用计数与垃圾回收:当某值的引用计数为0时,会被执行垃圾回收操作。
二、标记清除
1、循环引用:两个集和类型的变量,互为对方的元素时,可以通过对方的变量名互相间接引用,此为循环引用。这两个变量若同时被解除了其对应的各自集和的直接引用关系,但因为间接引的存在,虽然实质上无法被引用到,但按照引用计数的原则,不会被马上作为垃圾回收。
l1 = [111, ] # l1直接指向其列表的内存地址
l2 = [222, ] # l2直接指向其列表的内存地址
l1.append(l2) # l1=[值111的内存地址标记,l2列表的内存地址标记]
l2.append(l1) # l2=[值222的内存地址标记,l1列表的内存地址标记]
del l1 # 解除l1与其列表的直接引用关系,此时l1仍可以通过l2间接引用到原本列表
del l2 # 解除l2与其列表的直接引用关系,此时l1与l2都被解除了自身列表的直接引用关系,但是间接引用关系依然存在,但实际无法访问到
2、作用:为解决循环引用造成的内存泄露,简单来讲就是系统会按照某一规则对内存里的值进行引用计数的扫描,检测到这种只存在引用关系而实际无法被访问到的值会对其进行清除操作。
三、分代回收
1、作用:为了降低引用计数扫描的频率从而提升垃圾回收的效率。
2、机制:按照一定准则,对多次扫描结果正常的值进行标记,降低对其的扫描频率。