1、垃圾回收机制详解

1.1 引用计数

引用计数表示的是一个变量被引用的次数

例如:

x = 10  # 直接引用,10的引用计数变为1
print(id(x))
y = x  # 直接引用,10的引用计数变为2
z = x  # 直接引用,10的引用计数变为3
print(id(x),id(y),id(z))

 

这里提到了直接引用的概念,和它相对的还有间接引用.

如果x在容器类型(如列表和字典)中被使用即10被间接引用了,间接引用同样会增加引用计数

x = 10  # 直接引用,10的引用计数变为1
l = ['a', 'b', x]  # 间接引用,10的引用计数变为2
print(id(l[2]))  
d = {'mmm': x}  # 间接引用,10的引用计数变为3
print(id(d['mmm']))

 

引用的显著特点即他们的id都相同

 

在python中会自动将引用计数为0的变量值清除,回收其占有的内存空间,防止内存占用过高,这就是垃圾回收机制

 

 

1.2 标记清除

标记清除是一种用来解决循环引用时产生内存泄漏,即出现无法清除的变量值的方法.

lis1=[1,2,3]
lis2 = [2,3]
lis1.append(lis2)   # 此时lis1能间接引用lis2
lis2.append(lis1)   # 此时lis2能间接引用lis1
print(lis1)
print(lis2)
del lis1    # 解除变量名lis1和变量值的关系
del lis2    # 解除变量名lis2和变量值的关系
# 此时lis1里的数据与lis2里的数据都无法通过直接或间接引用的方法得到
# 但是之前列表内数据的引用计数不为0,他们还有间接引用的关系,无法直接被垃圾回收机制清除

 

此时我们必须引入新的方法,即标记清除

我们知道,变量名存放在栈中,变量值存放在堆内,python会在内存将满时使用标记清除,检测现存放在栈中的所有变量名,并对其标记为存活,接着进入堆内检测是否有和存活变量名完全无关的数据,一旦发 现就将它清除,这就是标记清除.

可以以一个简单易于理解的例子来解释:栈内的变量名就像树的根,堆内的变量值就像树的枝干,一旦一 棵树根全部被清除,树就无法存活,这时就需要将没有根的枝干全部清除.

 

1.3 分代回收

了解了python的垃圾回收机制,我们就要考虑一个问题,那就是回收垃圾的频率问题,如果无时无刻对所有的变量值进行检测,会占用大量的内存,我们需要尽量降低python的扫描频率,提高垃圾回收的效率,python中使用了分代回收来解决这一难题.

分代回收就是将变量值进行分代,分成使用频率不同的三代:新生代,中年代,老年代,

新变量都为新生代,在过程中动态检测变量值,扫描频率新生代最高,老年代最低,扫描多次依旧存活的变量会进入中年代或者老年代,减少部分变量值的扫描次数,以此达到提高效率,降低占用内存的目的.

 

 

 

 posted on 2020-03-05 17:15  wwwpy  阅读(402)  评论(0编辑  收藏  举报