7. 垃圾回收机制

垃圾回收机制(gc机制):garbage collection

我们在创建变量的时候,会申请内存空间,将变量内存地址和变量的值存储进去,在存储的时候,内存分为堆区和栈区,堆区存储变量的值,栈区存储的是变量名和变量值的内存地址
由于内存是有限的,所以应该定时对内存进行清理,将一些“垃圾及时的清理掉”

上面我们理解了堆区和栈区,堆区的一个数据没有变量指向它的时候,我们就无法访问到他了,他也就变成了一个“垃圾”,我们应该将这些“垃圾”及时的清除掉,腾出空间

引用计数:直接引用和间接引用都会将应用计数加一,引用计数为零的数据就是内存垃圾,需被清理(del能够将引用关系清除)

​ 直接引用:指的是从栈区出发直接引用到的内存地址

​ 间接引用:指的是从栈区出发引用到堆区后,在通过进一步引用才能到达的内存地址

容器类数据类型的内存原理:列表在内存中开辟一个空间,存储的是索引和索引对应值的内存地址,然后值的内存地址再指向值,字典的话,存储的就是键和值的内存地址(存的是变量的话,就是变量指向的数据的内存地址)

# 一个例题
x=10
l=[1,2,x]  # 相当于存放的是[数据1的内存地址,数据2的内存地址,10的内存地址]
x=123
print(l[2])
# 最后打印的结果还是10,不会改变

标记清除

循环引用:

l1=[111]
l2=[222]
l1.append(l2)  # [111的内存地址,l2列表的内存地址]
l2.append(l1)  # [222的内存地址,l1列表的内存地址]
# 相互引用,就是循环引用
del l1  # 删除l1的直接引用
del l2  # 删除l2的直接引用
# 一旦将直接引用摘掉之后,还剩下一个间接引用,两个数据都无法被访问到,但是两个数据还都不是垃圾,这样会造成无法清理的垃圾,这就叫内存泄漏
# 如何解决:标记清除

标记清除

​ 内存中分为很多区,有一个是栈区,栈区存放的是变量名和内存地址的映射关系,一个是堆区,堆区存放的是数据,当存在间接引用时,间接引用的地址都是存放在堆区里面的(上面例子中的[111的内存地址,l2列表的内存地址]全都存放在堆区里面),当删除直接引用之后,还存在间接引用,这时,python解释器会扫描栈区,将栈区中能够直接引用或者间接引用能够访问到的堆区中的数据标记为存活,不能访问的数据标记为非存活对象,应该删除,先标记都清除,所以叫标记清除机制

​ 变量的赋值,传参实际上传递的都是栈区的数据,栈的数据就是变量名与内存地址的对应关系

分代回收

​ 在历经多次扫描的情况下,都没有被回收的变量,gc机制就会认为,该变量是常用变量,gc对其扫描的频率会降低

​ 分代指的是根据存活时间来为变量划分不同等级(也就是不同的代)

​ 新定义的变量,放到新生代这个等级中,假设每隔1分钟扫描新生代一次,如果发现变量依然被引用,那么该对象的权重(权重本质就是个整数)加一,当变量的权重大于某个设定得值(假设为3),会将它移动到更高一级的青春代,青春代的gc扫描的频率低于新生代(扫描时间间隔更长),假设5分钟扫描青春代一次,这样每次gc需要扫描的变量的总个数就变少了,节省了扫描的总时间,接下来,青春代中的对象,也会以同样的方式被移动到老年代中。也就是等级(代)越高,被垃圾回收机制扫描的频率越低

​ 分代回收是为了解决标记清除时反复扫描内存效率低下的问题,是典型的空间换时间(扫描的时候需要记住变量引用次数)

posted @ 2021-07-20 00:19  奇点^  阅读(97)  评论(0)    收藏  举报