所有Python对象都被垃圾回收器跟踪吗?
我正在尝试调试一个内存泄漏的问题(可以查看这个问题 Python Twisted中的内存泄漏:它在哪里?)。
当垃圾回收器运行时,它能访问所有由Python解释器创建的对象吗?如果我们假设Python的C库没有内存泄漏,那么RSS内存使用量应该会随着垃圾回收对象数量的增加而线性增长吗?那sys.getobjects又是怎么回事呢?
3 个回答
一个设计成不能参与循环的Python类不会被垃圾回收器(GC)追踪。
class V(object):
__slots__ = ()
V的实例不能有任何属性。它的大小是16,和object()的大小一样。
使用sys.getsizeof(V())和v().sizeof()得到的值是一样的:16。
V本身没什么用,但我想象一下,如果有其他从基本类型(比如元组)派生的类,只是增加了一些方法,那么通过引用计数就足够管理它们的内存了。
RSS(驻留集大小)并不是随着Python对象数量的增加而线性增长,因为Python对象的大小是不同的。比如,一个int
对象通常比一个大的list
对象要小得多。
我猜你提到的sys.getobjects
其实是指gc.get_objects
。这个函数会给你一个所有可达对象的列表。如果你怀疑有内存泄漏,可以遍历这个列表,看看有没有应该被释放但还在的对象。(比如,你可能知道某种类型的所有对象应该在某个时刻被释放。)
CPython有两种方法来处理垃圾。第一种是引用计数,这种方法对所有对象都有效,但它无法处理那些相互引用的对象。这里就需要真正的垃圾收集器了:Python有一个叫做gc
的模块,它会查找那些可能形成循环引用的对象。只有那些可能参与循环引用的对象才需要担心被循环垃圾收集器处理。例如,列表会参与,但字符串不会;因为字符串不引用其他对象。(实际上,事情要复杂一点,因为参与循环垃圾收集有两种方式,但这里不太相关。)
所有的Python类(以及它们的实例)都会自动被循环垃圾收集器跟踪。用C语言定义的类型则不一定,除非它们做了一些额外的工作。所有可能形成循环的内置类型都会被跟踪。但这也意味着gc
模块只知道那些愿意配合的类型。
除了垃圾收集机制,Python还有自己的内存分配器(obmalloc),它会分配整块内存区域,并用这些内存来存储大部分小对象。现在,Python会在这些内存区域完全空的时候释放它们(之前很长一段时间是不会的),但实际上清空一个区域是相当少见的:因为CPython的对象是不可移动的,所以你不能简单地把一些剩余的对象移动到另一个区域。