Python C Api 和正确处理 C++ 类中的内存
Posted
技术标签:
【中文标题】Python C Api 和正确处理 C++ 类中的内存【英文标题】:Python C Api and correct handling of memory in C++ classes 【发布时间】:2013-01-07 13:34:40 【问题描述】:我想知道如何处理以下问题。在我的 C++ 类中,我有一个辅助 PyObject 指针。
class Foo
public:
// Should I new the dictionary here in constructor?
Foo()
// Must decrease the reference count or explicitly delete the dictionary?
~Foo()
Py_DECREF(myDictionary);
void sync()
myDictionary = PyDict_New();
for (int i=0; i<myInternalData.size(); i++)
PyObject *key = PyInt_FromLong(i);
PyObject *val = PyInt_FromLong(myInternalData.at(i));
PyDict_SetItem(dict,key,val);
Py_DecRef(key);
Py_DecRef(val);
private:
PyObject *myDictionary;
std::vector<int> myInternalData;
在我的 C++ 代码中,myInternalData
结构偶尔会更新或调整大小,我想知道如何处理我的 python 字典的正确内存分配。
我不知道如何释放与其关联的内存,或者如何正确地使其与我的内部 std::vector
保持同步,而不会破坏堆或引发内存泄漏。
对 Python C API 有帮助吗?我应该用PyObject_Del
释放PyDict,然后再次重新分配它吗?有人建议另一种方法?
【问题讨论】:
你经常打电话给sync
吗?据我所知,这可能是内存泄漏的来源,因为您正在分配新对象。另外(我在这里可能错了),我认为解除分配字典的适当方法可能是将 ref 计数器减少到零(docs.python.org/2/c-api/refcounting.html)。您是否尝试使用 valgrind 来查看您在哪里得到了内存泄漏?
【参考方案1】:
我不清楚你为什么在 Python 中使用字典,
当您使用一组连续的整数进行索引时,从 0 开始。
但是:在使用它之前,你必须做一个PyDict_New
来
创建字典。之后,当您重新同步时,您
应该在开始之前清除字典,使用
PyDict_Clear
,而不是重新分配一个新的..没有别的
应该是必要的。 (如果你重新分配一个新的,就像你在
你的代码,你应该减少旧的引用计数
一个第一。但是 Python 端的任何代码都引用了
旧的将继续引用旧的; PyDict_Clear
是
可能是更好的解决方案。)
另外,你应该注意临时 Python 对象的位置
参与其中。目前,没有其他必要了,因为
您只在循环中使用 Python(以及 C)函数,并且
它们不能触发 C++ 异常。永远改变代码
稍微,这可能不再是这种情况。作为基本规则,
我发现您应该将PyObject*
包装在一个类中
析构函数调用Py_DecRef
,而不是显式调用它,
可能会因为异常而错过电话。
【讨论】:
我在构造函数中移动了PyDict_New
,现在在sync
方法中我只调用PyDict_Clear(myDictionary)
。我还在析构函数中添加了Py_DECREF(myDictionary)
,现在所有的内存泄漏都被消除了!以上是关于Python C Api 和正确处理 C++ 类中的内存的主要内容,如果未能解决你的问题,请参考以下文章