我是Python及其C API的新手。我仍然不明白引用计数是如何工作的。我已经编写了一个粒子跟踪模块,它向python公开了我过去编写和测试过的许多C ++线程跟踪函数。 (据我所知,他们自己没有内存泄漏)。
当我在Python中反复调用其中一个函数时,我可以看到内存使用量正在缓慢增长。我相信某处存在内存泄漏(可能无处不在:O) 我复制了主跟踪功能的相关片段下面,以便有人可以指向我是否应该调用Py_DECREFs(例如,在item_py上?)
PyObject* _track_particles() {
// more code here ... (no Python/C API calls)
PyObject* result_py = PyTuple_New(particles.size());
for(int i=0; i<particles.size(); ++i) {
PyObject* item_py = PyTuple_New(2);
if (lost_at_turn_idx[i] == PARTICLE_NOT_LOST) {
int offset = i * (nr_turns+1) * 6 + nr_turns * 6;
PyTuple_SetItem(item_py, 0, Py_True);
PyTuple_SetItem(item_py, 1, Py_BuildValue("(dddddd)",
data_out[offset + rx], data_out[offset + px],
data_out[offset + ry], data_out[offset + py],
data_out[offset + de], data_out[offset + dl]));
} else {
PyTuple_SetItem(item_py, 0, Py_False);
PyTuple_SetItem(item_py, 1,
Py_BuildValue("(ii)", lost_at_turn_idx[i],
lost_at_element_idx[i]));
}
PyTuple_SetItem(result_py, i, item_py);
}
return result_py;
}
ps:发现this reference有用
答案 0 :(得分:1)
this是否相关?
使用
t = PyTuple_New(n)
代替,并使用PyTuple_SetItem(t, i, o)
填充对象 - 请注意,这会“引用”o
的引用计数,因此您必须Py_INCREF()
它。
我不完全确定这段经文是否清楚,但这可能是一个很好的起点。
答案 1 :(得分:0)
编辑:非常感谢@DavidW 向我指出这一点(见评论)。你definitely need to Py_INCREF
Py_True
and Py_False
。当你做了不应该做的事情时,C 会做一些奇怪的事情,但很难说这是否会导致你的内存问题。
晚了几年,但老实说,你的代码看起来没问题。 result_py
正在返回,因此只需要由 Py_DECREF
的调用者_track_particles
'd(我假设您的 C++ 代码中有 _track_particles
的调用者,因为有PyObject *self
,PyObject *args
在其签名中定义)而 item_py
引用被 PyTuple_SetItem
窃取。 PyTuple_SetItem
窃取了您的其余新引用,因此这也不是问题。有趣的是,您给出了一个不需要单个 Py_DECREF
的代码片段。
您如何检查内存泄漏?我知道这是旧的,但 Python 3 带有 tracemalloc,所以你可以用它包装一个函数调用来检查。