PythonPyObject中的Cextension称为Py_DECREF,引用为0,但内存泄漏

2024-10-03 17:19:35 发布

您现在位置:Python中文网/ 问答频道 /正文

这是我的密码

PyObject *dataPyParams = PyList_New(0);
for (int i = 0; i < figdata.dataSetList.size(); i++)
{
    PyObject *pyParams = PyList_New(0);
    for (int j = 0; j < figdata.dataSetList[i].size(); j++)
    {
        //std::cerr << figdata.dataSetList[i][j] << "data\n";
        auto temp = Py_BuildValue("f", figdata.dataSetList[i][j]);
        PyList_Append(pyParams,temp);
        Py_DECREF(temp);    
    }
    PyList_Append(dataPyParams, pyParams);
    Py_DECREF(pyParams);
    
}
Py_DECREF(dataPyParams);

我调用了Py_DECREF(dataPyParams),dataPyParams引用是0,但内存不是空闲的。 我试着删除PyList_Append(pyParams,temp),这样可以释放内存。这让我很烦恼


Tags: 内存pynewforsizetempintpyobject
1条回答
网友
1楼 · 发布于 2024-10-03 17:19:35

Python(和大多数语言)不会直接满足操作系统的内存分配,也不会在发布时立即返回分配。它批量分配,并通过分区块来满足较小的请求。即使一个块中的所有内存都被“释放”,它也不总是返回操作系统,而是保留下来以备将来分配

在本例中,您正在创建floatlist对象,这两个对象都有自己的“空闲列表”,因此释放并不实际上将它们返回给分配器,而是返回给一个简单的已分配但未使用的对象堆栈,floatlist构造函数可以从中提取这些对象,比向分配器请求更多内存更便宜。问题是,这也意味着这些元素所在的块根本无法返回到操作系统,因为至少从分配器的角度来看,部分元素仍然被分配。您可以通过显式调用PyGC_Collect()(仅通过a What's New doc中的副作用记录)清除这些空闲列表,这可能允许内存返回到操作系统,但同样,这也不能保证。您可能还需要want to disable ^{}(以避免额外的小对象竞技场,这些竞技场甚至不太可能交回操作系统)。尽管如此,Python仍完全有权无限期地保留大部分内存以满足未来的分配

简而言之,这可能不是内存泄漏。您可以使用更高级的内存分析工具(如果没有其他工具的话,如果您在启动之前在您的环境中定义^{},Python本身将告诉您竞技场的使用情况),但是任务管理器只能看到操作系统看到的内容,而不能看到Python本身在原始、大容量操作系统内存分配上分层的内部内存管理

在没有外部工具的情况下,一个简单的测试就是多次运行这个精确的代码(包括清理)。如果每次运行时内存都以固定的大幅度增加,那么是的,可能是内存泄漏。但更可能的是,您会发现第一次运行消耗了大量内存,但后续运行只增加了很少或根本没有内存使用(有些可能会由于分配顺序和分配对齐问题而被使用,但会非常小),因为它们使用的是释放的内存(在userland中,而不是操作系统中)而不是要求操作系统提供更多内存

相关问题 更多 >