NumPy C API 扩展导致内存使用过多
NumPy C API extension causes excessive memory usage
我已经为 NumPy 编写了一个 C 扩展来加速我的一些计算,但是当我重复调用该函数时,我的内存使用量越来越大。我已将函数缩减为最小示例:
PyObject* memory_test_function(PyObject* self, PyObject* args)
{
PyArrayObject *ang;
int i;
if (!PyArg_ParseTuple(args, "O", &ang)) return NULL;
int L0 = (int) PyArray_DIMS(ang)[0];
// ballooning memory usage
npy_intp final_out_dims[2] = {L0,1};
PyObject *output_array;
output_array = PyArray_SimpleNew(2, final_out_dims, NPY_FLOAT64);
Py_INCREF(output_array);
for (i=0;i<L0;i++)
{
*(double *)PyArray_GETPTR2(output_array,i,0) =
tan(*(double *)PyArray_GETPTR2(ang,i,0));
}
return PyArray_Return(output_array);
/* constant memory usage
double sum=0.0;
for (i=0;i<L0;i++) sum+=tan(*(double *)PyArray_GETPTR2(ang,i,0));
return PyFloat_FromDouble(sum); */
}
问题似乎是由创建输出数组引起的,因为只返回一个浮点数而不创建数组对象在内存中是常量。我怀疑 INCREF/DECREF 有问题,但我认为我做的一切都是正确的。重复调用此函数(一百万次左右)会使内存使用量随时间线性增加,这让我觉得有些东西没有被正确地垃圾收集。手动使用 gc
没有帮助。如果有什么明显的遗漏,请告诉我!
PyArray_SimpleNew
在后台调用(可能是间接调用)_Py_NewReference
。此函数将新创建的引用的引用计数设置为 1。
您随后的 Py_INCREF
将引用计数增加到 2,从而确保 Python 永远不会释放该对象,即使对它的所有引用都不复存在,因为它的引用计数永远不会下降到 0.
Py_INCREF
调用是不必要的,因为您没有 与此处的任何其他对象共享 引用,您只是在本地使用它,然后将其传递给来电者。
我已经为 NumPy 编写了一个 C 扩展来加速我的一些计算,但是当我重复调用该函数时,我的内存使用量越来越大。我已将函数缩减为最小示例:
PyObject* memory_test_function(PyObject* self, PyObject* args)
{
PyArrayObject *ang;
int i;
if (!PyArg_ParseTuple(args, "O", &ang)) return NULL;
int L0 = (int) PyArray_DIMS(ang)[0];
// ballooning memory usage
npy_intp final_out_dims[2] = {L0,1};
PyObject *output_array;
output_array = PyArray_SimpleNew(2, final_out_dims, NPY_FLOAT64);
Py_INCREF(output_array);
for (i=0;i<L0;i++)
{
*(double *)PyArray_GETPTR2(output_array,i,0) =
tan(*(double *)PyArray_GETPTR2(ang,i,0));
}
return PyArray_Return(output_array);
/* constant memory usage
double sum=0.0;
for (i=0;i<L0;i++) sum+=tan(*(double *)PyArray_GETPTR2(ang,i,0));
return PyFloat_FromDouble(sum); */
}
问题似乎是由创建输出数组引起的,因为只返回一个浮点数而不创建数组对象在内存中是常量。我怀疑 INCREF/DECREF 有问题,但我认为我做的一切都是正确的。重复调用此函数(一百万次左右)会使内存使用量随时间线性增加,这让我觉得有些东西没有被正确地垃圾收集。手动使用 gc
没有帮助。如果有什么明显的遗漏,请告诉我!
PyArray_SimpleNew
在后台调用(可能是间接调用)_Py_NewReference
。此函数将新创建的引用的引用计数设置为 1。
您随后的 Py_INCREF
将引用计数增加到 2,从而确保 Python 永远不会释放该对象,即使对它的所有引用都不复存在,因为它的引用计数永远不会下降到 0.
Py_INCREF
调用是不必要的,因为您没有 与此处的任何其他对象共享 引用,您只是在本地使用它,然后将其传递给来电者。