从分配的数组在 C 中创建 numpy 数组会导致内存泄漏



我已经将程序中的内存泄漏追溯到我用 C 编写的 Python 模块,以有效地解析以 ASCII-hex 表示的数组。(例如"FF 39 00 FC ...")

char* buf;
unsigned short bytesPerTable;
if (!PyArg_ParseTuple(args, "sH", &buf, &bytesPerTable))
{
    return NULL;
}
unsigned short rowSize = bytesPerTable;
char* CArray = malloc(rowSize * sizeof(char));
// Populate CArray with data parsed from buf
ascii_buf_to_table(buf, bytesPerTable, rowSize, CArray);
int dims[1] = {rowSize};
PyObject* pythonArray = PyArray_SimpleNewFromData(1, (npy_intp*)dims, NPY_INT8, (void*)CArray);
return Py_BuildValue("(O)", pythonArray);

我意识到numpy不知道释放分配给CArray的内存,从而导致内存泄漏。在对这个问题进行了一些研究之后,在本文的评论建议下,我添加了以下行,该行应该告诉数组它"拥有"其数据,并在删除时释放它。

PyArray_ENABLEFLAGS((PyArrayObject*)pythonArray, NPY_ARRAY_OWNDATA);

但我仍然得到内存泄漏。我做错了什么?如何使NPY_ARRAY_OWNDATA标志正常工作?

作为参考,ndarraytypes.h 中的文档看起来应该可以工作:

/*
 * If set, the array owns the data: it will be free'd when the array
 * is deleted.
 *
 * This flag may be tested for in PyArray_FLAGS(arr).
 */
#define NPY_ARRAY_OWNDATA         0x0004

同样作为参考,以下代码(调用 C 中定义的 Python 函数)演示了内存泄漏。

tableData = "FF 39 00 FC FD 37 FF FF F9 38 FE FF F1 39 FE FC n" 
            "EF 38 FF FE 47 40 00 FB 3D 3B 00 FE 41 3D 00 FE n" 
            "43 3E 00 FF 42 3C FE 02 3C 40 FD 02 31 40 FE FF n" 
            "2E 3E FF FE 24 3D FF FE 15 3E 00 FC 0D 3C 01 FA n" 
            "02 3E 01 FE 01 3E 00 FF F7 3F FF FB F4 3F FF FB n" 
            "F1 3D FE 00 F4 3D FE 00 F9 3E FE FC FE 3E FD FE n" 
            "F6 3E FE 02 03 3E 00 FE 04 3E 00 FC 0B 3D 00 FD n" 
            "09 3A 00 01 03 3D 00 FD FB 3B FE FB FD 3E FD FF n"
for i in xrange(1000000):
    PES = ParseTable(tableData, 128, 4) //Causes memory usage to skyrocket

这可能是一个引用计数问题(来自如何扩展 NumPy):

引用计数错误的一个常见来源是Py_BuildValue函数。请特别注意"N"格式字符和"O"格式字符之间的区别。如果您在子例程(例如输出数组)中创建一个新对象,并且您要在返回值的元组中将其传递回,那么您最有可能在Py_BuildValue中使用"N"格式字符。"O"字符会将引用计数增加 1。这将给调用方留下一个全新数组的两个引用计数。当删除变量并且引用计数减少 1 时,仍将存在该额外的引用计数,并且数组将永远不会被解除分配。您将遇到引用计数引起的内存泄漏。使用"N"字符将避免这种情况,因为它将向调用方返回具有单个引用计数的对象(元组内)。

相关内容

  • 没有找到相关文章

最新更新