python - 调试 Python C 扩展模块中的引用计数内存泄漏

标签 python c memory-leaks garbage-collection

我正在尝试确定 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/

相关文章:

python - 错误 : "Resample() got an unexpected keyword argument ' how'"

Python 按名称排序

c++ - 在 Mysql ODBC 中禁用 GUI

C - 我的代码在一个文件中有效,但在另一个文件中无效

Cppcheck : (error) Resource leak

python - 如何提取具有特定值的numpy数组的最后一行和第一行

jquery - 有什么方法可以使用jinja2和flask形式而不是ajax和jquery或两者都使用?

c - 为什么我的999999999的float变成了10000000000?

ios - block 和内存泄漏

ios - 两个完全相同的代码,但其中一个代码有僵尸问题