我正在尝试确定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
我似乎无法在date
返回的对象列表中找到泄漏的gc.get_objects()
对象:
>>> from datetime import date
>>> print [obj for obj in gc.get_objects() if isinstance(obj, date)]
[]
我在这里错过了关于gc.get_objects()
如何运作的内容吗?有没有其他方法来证明memleak()函数有内存泄漏?
答案 0 :(得分:2)
来自gc
模块的文档:
由于收集器补充已使用的引用计数 在Python中,如果您确定您的程序,则可以禁用收集器 不会创建参考周期。
因此gc
模块仅使用 来处理引用周期。在您的情况下,没有循环,因此date
函数不返回get_objects
对象。
事实上,旧版本的python根本没有垃圾收集器,它们只使用引用计数。引入垃圾收集器是为了避免使用引用循环创建内存泄漏(因为这可以很容易地从python端完成,并且你不希望纯python程序创建内存泄漏)。
要查看那种内存泄漏,你应该在循环中调用memleak
函数,看看使用的内存是否增加(在你的情况下慢慢)。
还有一些第三方库可用于分析内存使用情况,请参阅SO上的Which Python memory profiler is recommended?问题。
答案 1 :(得分:1)
对于此类调试,您希望使用使用--with-pydebug
选项编译的Python实例。调试模式启用的功能之一是通过sys
模块中的新功能跟踪参考计数总数 - gettotalrefcount()
。
有关详细信息,请参阅http://docs.python.org/3/c-api/intro.html#debugging-builds
答案 2 :(得分:-3)
#include <Python.h>
#include <datetime.h>
static PyObject* memleak(PyObject *self, PyObject *args) {
PyObject* date=PyDate_FromDate(2000, 1, 1); /* deliberately create a memory leak */
Py_DECREF(date);
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);
}
解决您的问题Py_DECREF(日期);