【问题标题】:Memory Leaks and Reference Counting in Python/C APIPython/C API 中的内存泄漏和引用计数
【发布时间】:2012-11-03 00:00:57
【问题描述】:

我对 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很有用

【问题讨论】:

  • (probably everywhere :O) 哈哈

标签: python memory-leaks python-module python-c-api reference-counting


【解决方案1】:

this 相关吗?

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

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

【讨论】:

  • 但是我已经在使用 PyTuple_New 了。对不起,我没有理解你的建议......
  • 我没有提出建议。我引用了 Python FAQ。
【解决方案2】:

编辑:非常感谢@DavidW 向我指出这一点(参见 cmets)。你definitely need to Py_INCREF Py_True and Py_False。当你做你不应该做的事情时,C 会做一些奇怪的事情,但很难说这是否会导致你的记忆问题。

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

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

【讨论】:

  • PyTuple_SetItem(item_py, 0, Py_True); 绝对不行。它将Py_True 添加到一个元组而不增加它,所以它将以Py_True 被释放结束。但这不是内存泄漏。
  • 哎呀,不错的选择。是的,对于那些特别的Py_TruePy_FalsePy_None 家伙Py_INCREF 是必需的。我会在编辑中提到这一点。谢谢!
猜你喜欢
  • 2019-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 2012-10-01
相关资源
最近更新 更多