【发布时间】:2019-07-16 12:30:11
【问题描述】:
我对 Python 比较陌生,这是我第一次尝试编写 C 扩展。
背景 在我的 Python 3.X 项目中,我需要加载和解析大型二进制文件 (10-100MB) 以提取数据以进行进一步处理。二进制内容以帧的形式组织:标题后跟可变数量的数据。由于 Python 的性能较低,我决定使用 C 扩展来加速加载部分。
独立的 C 代码比 Python 的性能高出 20 倍到 500 倍,所以我对它非常满意。
问题:当我在同一个 Python 模块中多次调用 C 扩展中的函数时,内存不断增长。
my_c_ext.c
#include <Python.h>
#include <numpy/arrayobject.h>
#include "my_c_ext.h"
static unsigned short *X, *Y;
static PyObject* c_load(PyObject* self, PyObject* args)
{
char *filename;
if(!PyArg_ParseTuple(args, "s", &filename))
return NULL;
PyObject *PyX, *PyY;
__load(filename);
npy_intp dims[1] = {n_events};
PyX = PyArray_SimpleNewFromData(1, dims, NPY_UINT16, X);
PyArray_ENABLEFLAGS((PyArrayObject*)PyX, NPY_ARRAY_OWNDATA);
PyY = PyArray_SimpleNewFromData(1, dims, NPY_UINT16, Y);
PyArray_ENABLEFLAGS((PyArrayObject*)PyY, NPY_ARRAY_OWNDATA);
PyObject *xy = Py_BuildValue("NN", PyX, PyY);
return xy;
}
...
//More Python C-extension boilerplate (methods, etc..)
...
void __load(char *) {
// open file, extract frame header and compute new_size
X = realloc(X, new_size * sizeof(*X));
Y = realloc(Y, new_size * sizeof(*Y));
X[i] = ...
Y[i] = ...
return;
}
test.py
import my_c_ext as ce
binary_files = ['file1.bin',...,'fileN.bin']
for f in binary_files:
x,y = ce.c_load(f)
del x,y
这里我删除返回的对象,希望降低内存使用量。
在阅读了几篇帖子(例如this、this 和this)后,我仍然卡住了。
我尝试添加/删除 PyArray_ENABLEFLAGS 设置 NPY_ARRAY_OWNDATA 标志而没有遇到任何差异。我尚不清楚NPY_ARRAY_OWNDATA 是否暗示 C 中的 free(X)。如果我在 C 中显式释放数组,则在尝试在test.py 的 for 循环中加载第二个文件时遇到segfault .
知道我做错了什么吗?
【问题讨论】:
标签: python memory-leaks python-c-api reference-counting