1

我对 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:发现这个参考有用

4

2 回答 2

1

这相关吗

改为使用t = PyTuple_New(n),并用对象填充它PyTuple_SetItem(t, i, o)- 请注意,这会“吃掉” 的引用计数o,所以你必须这样Py_INCREF()做。

我不完全确定这段话是否清楚,但这可能是一个很好的起点。

于 2012-11-14T13:32:21.553 回答
0

编辑:非常感谢@DavidW 向我指出这一点(见评论)。你肯定需要Py_INCREF Py_TrueandPy_False。当你做你不应该做的事情时,C 会做一些奇怪的事情,但很难说这是否会导致你的记忆问题。

晚了几年,但老实说,你的代码看起来不错result_py正在被返回,因此只需要Py_DECREF由调用者_track_particles(我假设_track_particles在你的 C++ 代码中有一个调用者,因为在它的签名PyObject *self中定义了),而引用被. 您的其他新参考资料被盗,所以这也不是问题。有趣的是,您给出了一个不需要单个的代码片段。PyObject *argsitem_pyPyTuple_SetItemPyTuple_SetItemPy_DECREF

你如何检查你的内存泄漏?我知道这很旧,但是 Python 3 带有tracemalloc,所以你可以用它包装一个函数调用来检查。

于 2021-01-16T05:55:28.827 回答