python垃圾回收主要采用的是引用计数为主,标记清除和分代回收为辅的策略。
1.引用计数(reference counting)
1.1 原理
python语言默认采取的垃圾回收机制是引用计数。其原理是:每个对象维护一个ob_ref字段,用来记录该对象当前被引用的次数。每当新的引用对象指向该对象时,它的引用计数ob_ref加1;每当该对象的引用失效时,引用计数ob_ref减1。一旦对象的引用计数为0,该对象立即被回收,对象占用的内存空间将被释放。
1.2 引用计数查看
通过sys.getrefcount()来获取一个名称所引用的对象的引用计数情形
import sys
print(sys.getrefcount(123))
a=123
print(sys.getrefcount(123))
result:
7
8
1.2 引用计数增加的情形
对象被创建
x=5
对象被引用
a='people'
b=a
作为容器对象的一个元素
a='name'
list1 = [a, 'sex']
作为参数进行传递
a='name'
foo(a)
对对象使用sys.getrefcount()
import sys
print(sys.getrefcount(123))
a=123
print(sys.getrefcount(123))
result:
7
8
1.3 引用计数减少的情形
对象被删除
x=5
del x
对象的别名被赋值给其他对象
x ="aaa"
对象被从一个窗口中移除
list1 = ['name', 'sex']
list1.remove('sex')
对象离开了它的作用域 foo(x)函数结束后
def func(x):
return x**2
窗口对象被销毁
list1 = ['name', 'sex']
del list1
1.4 优缺点
1.4.1 优点
引用计数法具有明显的优点,比如高效、实现逻辑简单、具备实时性,一旦一个对象的引用计数归零,内存就直接释放了。不用像其他机制等到特定时机。将垃圾回收随机分配到运行的阶段,处理回收内存的时间分摊到了平时,正常程序的运行比较平稳。
1.4.2 缺点
引用计数的第一个缺点是实现麻烦。每个对象都需要分配单独的空间来统计引用计数,需要浪费空间,且需要对引用计数进行维护,维护时容易出错。
引用计数的第二个缺点是在一些场景下可能运行比较慢。正常来说垃圾回收会平稳运行,但是当需要释放一个比较大的对象(如字典),需要对引用的所有对象循环嵌套调用,从而会花费比较长的时间。
引用计数的第三个缺点是循环引用,引用计数无法解决该问题。