Python中的gc模块封装了许多和对象以及垃圾回收相关的方法。
导致引用计数+1的情况:
- 对象被创建,并被一个对象所引用。例如
a=23
- 对象被另外一个变量引用。例如
b=a
。 - 对象被作为参数传递给函数。例如
func(a)
。 - 对象被添加到容器中,比如添加到列表、元组、字典、集合中等。例如
temp=[a]
。
导致引用计数-1的情况:
- 引用这个对象的变量被删掉掉了。例如
del a
。 - 引用这个对象的变量指向其他的对象了。例如
a='abc'
。 - 函数作用域执行完毕后。比如一个函数中的临时变量,在这个函数执行结束后就会消失。
- 对象所在的这个容器被销毁,或者从这个容器中删除了这个对象,也会导致这个对象引用计数会减1。
查看一个对象的引用计数:
import sys
a = "hello world"
print(sys.getrefcount(a))
打印出来的引用计数,总是会比真实的引用计数多1,原因是因为你将这个对象传给了getrefcount
函数,这个过程会给这个对象的引用计数加1.``
gc模块常用函数:
-
gc.set_debug(flags)
:设置gc
的debug
日志,一般设置为gc.DEBUG_LEAK
可以看到内存泄漏的对象。 -
gc.collect(generation)
:执行垃圾回收。会将那些有循环引用的对象给回收了。这个函数可以传递参数,0
代表只回收第0代的的垃圾对象,1
代表回收第0代和第1代的对象,2
代表回收第0、1、2代的对象。如果不传参数,那么会使用2
作为默认参数。 -
gc.get_threshold()
:获取gc模块执行垃圾回收的阈值。返回的是个元组,第0
个是零代的阈值,第1个是1代的阈值,第2个是2代的阈值。 -
gc.set_threshold()
:设置执行垃圾回收的阈值。 -
gc.get_count()
:获取当前自动执行垃圾回收的计数器。返回一个元组。第0个是零代的垃圾对象的数量,第1个是零代链表遍历的次数,第2个是1代链表遍历的次数。
关于阈值和垃圾回收:
假设通过gc.get_threshold()
返回的是(700,10,10)
,那么意味着只要零代垃圾值到了700
,就会执行gc.collect(0)
,回收零代的垃圾值;只要1代垃圾值到了10
,就会执行gc.collect(1)
,回收零代和1代的垃圾值。只要2
代垃圾值到了10
,就会执行gc.collect(2),回收零代和1代以及2代的垃圾值。
注意点:
gc
模块不能处理的是,如果两个循环引用的对象都实现了__del__
方法,那么将不会进行垃圾回收,因此尽量不要在类中实现自己的__del__
方法。否则发生循环引用后就会产生内存泄露。