我正在尝试确定 Python C 扩展模块中是否存在任何引用计数内存泄漏。考虑这个泄漏 date
对象的非常简单的测试扩展:
#include <Python.h>
#include <datetime.h>
static PyObject* memleak(PyObject *self, PyObject *args) {
PyDate_FromDate(2000, 1, 1); /* deliberately create a memory leak */
Py_RETURN_NONE;
}
static PyMethodDef memleak_methods[] = {
{"memleak", memleak, METH_NOARGS, "Leak some memory"},
{NULL, NULL, 0, NULL} /* Sentinel */
};
PyMODINIT_FUNC initmemleak(void) {
PyDateTime_IMPORT;
Py_InitModule("memleak", memleak_methods);
}
PyDate_FromDate 创建一个新的引用(即在内部调用 Py_INCREF)并且因为我从不调用 Py_DECREF,所以这个对象永远不会被垃圾收集。
但是,当我调用这个函数时,垃圾收集器跟踪的对象数量在函数调用前后似乎没有变化:
Python 2.7.3 (default, Apr 10 2013, 05:13:16)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from memleak import memleak
>>> import gc
>>> gc.disable()
>>> gc.collect()
0
>>> len(gc.get_objects()) # get object count before
3581
>>> memleak()
>>> gc.collect()
0
>>> len(gc.get_objects()) # get object count after
3581
而且我似乎在 gc.get_objects()
返回的对象列表中根本找不到泄漏的 date
对象:
>>> from datetime import date
>>> print [obj for obj in gc.get_objects() if isinstance(obj, date)]
[]
我是否遗漏了一些有关 gc.get_objects()
工作原理的信息?有没有其他方法可以证明 memleak() 函数存在内存泄漏?
最佳答案
来自 gc
的文档模块:
Since the collector supplements the reference counting already used in Python, you can disable the collector if you are sure your program does not create reference cycles.
因此 gc
模块仅用于处理循环引用。在您的情况下,没有循环,因此 date
对象不会由 get_objects
函数返回。
其实老版本的python根本就没有垃圾回收器,他们只用了引用计数。引入垃圾收集器是为了避免使用引用循环造成内存泄漏(因为这可以很容易地从 python 端完成,并且您不希望纯 python 程序造成内存泄漏)。
要查看那种内存泄漏,您应该在循环中调用 memleak
函数,然后查看使用的内存增加(在您的情况下缓慢增加)。
还有一些第 3 方库可用于分析内存使用情况,请参阅 Which Python memory profiler is recommended?关于 SO 的问题。
关于python - 调试 Python C 扩展模块中的引用计数内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18693744/