这是内存泄漏吗?

5 投票
2 回答
1090 浏览
提问于 2025-04-16 04:29

我正在使用gc模块来调试一个内存泄漏的问题。

这是一个图形界面程序,我把这个功能绑定到了一个按钮上。

我把调试模式设置为 gc.SAVE_ALL

> gc.collect()
> 
> print gc.garbage

这是输出的内容

[(<type '_ctypes.Array'>,), {'__module__': 'ctypes._endian', '__dict__': <attribute '__dict__' of 'c_int_Array_3' objects>, '__weakref__': <attribute '__weakref__' of 'c_int_Array_3' objects>, '_length_': 3, '_type_': <class 'ctypes.c_int'>, '__doc__': None}, <class 'ctypes._endian.c_int_Array_3'>, <attribute '__dict__' of 'c_int_Array_3' objects>, <attribute '__weakref__': <attribute '__weakref__' of 'c_int_Array_3' objects>, (<class 'ctypes._endian.c_int_Array_3'>, <type '_ctypes.Array'>, <type '_ctypes._CData'>, <type 'object'>), (<type '_ctypes.CFuncPtr'>,), {'__module__': 'ctypes', '__dict__': <attribute '__dict__' of '_FuncPtr' objects>, '__weakref__': <attribute '__weakref__' of '_FuncPtr' objects>, '_flags_': 1, '__doc__': None, '_restype_': <class 'ctypes.c_int'>}, <class 'ctypes._FuncPtr'>, <attribute '__dict__' of '_FuncPtr' objects>, <attribute '__weakref__': <attribute '__weakref__' of '_FuncPtr' objects>, (<class 'ctypes._FuncPtr'>, <type '_ctypes.CFuncPtr'>, <type '_ctypes._CData'>, <type 'object'>), {}, <cell at 0x10a24b0: Resource object at 0x10e6a50>, <cell at 0x10a2478: dict object at 0x11a4440>, <cell at 0x7f1703949f68: function object at 0x10ec7d0>, <cell at 0x10e2f30: NoneType object at 0x826880>, <cell at 0x10e2d70: NoneType object at 0x826880>, <cell at 0x10e2ef8: str object at 0x7f1703dd5e10>, <cell at 0x10e2de0: dict object at 0x118aaa0>, {'Accept': 'application/json', 'User-Agent': 'couchdb-python 0.6'}, (<cell at 0x10e2f30: NoneType object at 0x826880>, <cell at 0x10a24b0: Resource object at 0x10e6a50>, <cell at 0x10e2de0: dict object at 0x118aaa0>, <cell at 0x10a2478: dict object at 0x11a4440>, <cell at 0x10e2d70: NoneType object at 0x826880>, <cell at 0x10e2ef8: str object at 0x7f1703dd5e10>, <cell at 0x7f1703949f68: function object at 0x10ec7d0>), <function _make_request at 0x10ec7d0>, (1,), {}, <cell at 0x10e2bb0: Resource object at 0x10e6a50>, <cell at 0x10e2e88: dict object at 0x119f360>, <cell at 0x10f0130: function object at 0x10ec578>, <cell at 0x10f01d8: NoneType object at 0x826880>, <cell at 0x10f01a0: NoneType object at 0x826880>, <cell at 0x10f00f8: str object at 0x7f170b05d810>, <cell at 0x10f00c0: dict object at 0x11969a0>, {'Accept': 'application/json', 'User-Agent': 'couchdb-python 0.6'}, (<cell at 0x10f01d8: NoneType object at 0x826880>, <cell at 0x10e2bb0: Resource object at 0x10e6a50>, <cell at 0x10f00c0: dict object at 0x11969a0>, <cell at 0x10e2e88: dict object at 0x119f360>, <cell at 0x10f01a0: NoneType object at 0x826880>, <cell at 0x10f00f8: str object at 0x7f170b05d810>, <cell at 0x10f0130: function object at 0x10ec578>), <function _make_request at 0x10ec578>, (1,), {}, <cell at 0x10f0440: Resource object at 0x10e6a50>, <cell at 0x10f02b8: dict object at 0x11b2d70>, <cell at 0x10f0360: function object at 0x10ec6e0>, <cell at 0x10f0280: NoneType object at 0x826880>, <cell at 0x10f02f0: str object at 0x10ca228>, <cell at 0x10f0408: str object at 0x7f170b05d810>, <cell at 0x10f0050: dict object at 0x11b6370>, {'Accept': 'application/json', 'User-Agent': 'couchdb-python 0.6'}, (<cell at 0x10f0280: NoneType object at 0x826880>]

gc.garbage列表里有很多项。这是否意味着gc.garbage里的对象正在泄漏,或者已经被回收,或者将会被回收?

2 个回答

0

在其他编程语言中,我用过一种叫做堆分析器的工具,效果很好,可以帮助我找到内存泄漏的问题。在Python中我还没用过这种工具,不过Heapy看起来值得一试。

在他们的“数据处理”部分,可以试试这个功能:

  • 从一组根对象中计算出“被支配”的对象集合,这样可以找出如果根对象被释放了,哪些对象也会被释放。

如果这个工具和其他工具类似,你应该能逐步深入分析。跟踪那些“被支配”对象集合最大的对象,直到你发现某个对象的大小似乎过大,那很可能就是内存泄漏的地方。

1

来自文档的内容:

gc.garbage

这是一个列表,里面包含了那些垃圾回收器发现无法到达但又无法释放的对象(也就是不可回收的对象)。

所以我觉得这看起来像是一种内存泄漏。接下来,文档解释了可能导致这种情况的原因:

如果对象有del()方法,并且它们形成了一个引用循环,那么整个循环就会变得无法回收,包括那些不在循环中但只能通过这个循环访问的对象。Python不会自动回收这样的循环,因为通常情况下,Python无法猜测出一个安全的顺序来运行del()方法。如果你知道一个安全的顺序,可以通过检查垃圾列表来强制解决这个问题,并明确打破你列表中对象的循环。需要注意的是,这些对象因为在垃圾列表中而仍然被保留,所以也应该从垃圾中移除。例如,在打破循环后,可以使用 del gc.garbage[:] 来清空这个列表。通常来说,最好是避免创建包含del()方法的对象的循环,这样可以通过检查垃圾来确认没有创建这样的循环。

现在,如果设置了DEBUG_SAVEALL标志,所有的垃圾都会泄漏。来自同一来源:

gc.DEBUG_SAVEALL

当这个标志被设置时,所有无法到达的对象都会被添加到垃圾列表中,而不是被释放。这在调试内存泄漏的程序时非常有用。

所以,再次强调,是的,那份列表就是泄漏的内存。但是你是自己选择让它泄漏的!

撰写回答