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 调用是不必要的,因为您没有 与此处的任何其他对象共享 引用,您只是在本地使用它,然后将其传递给来电者。