【问题标题】:How to return a cached PyObject* value several times without memory leaking or double/triple frees?如何多次返回缓存的 PyObject* 值而不发生内存泄漏或双/三释放?
【发布时间】:2019-05-23 13:47:33
【问题描述】:

关于我的最后一个问题How to improve Python C Extensions file line reading? 提出了一些我遇到的内存问题。然后,我写了这个简单而荒谬的 Python C Extension 用法,目的只是为了更好地理解 Python Borrowing and Owning References。

static void PyFastFile_dealloc(PyFastFile* self) {
    for( PyObject* pyobject : linecache ) {
        Py_XDECREF( pyobject );
    }
    Py_TYPE(self)->tp_free( (PyObject*) self );
}

static PyObject* PyFastFile_tp_iter(PyFastFile* self, PyObject* args) {
    counter = 10;
    std::string line{"sample line"}
    PyObject* obj = PyUnicode_DecodeUTF8( line.c_str(), line.size(), "replace" );
    linecache.push_back( obj );
}

static PyObject* PyFastFile_iternext(PyFastFile* self, PyObject* args) {
    --counter;

    if( !( counter ) ) {
        PyErr_SetNone( PyExc_StopIteration );
        return NULL;
    }

    PyObject* retval = linecache[0];
    Py_XINCREF( retval );
    return retval;
}

// create the module
PyMODINIT_FUNC PyInit_fastfilepackage(void) {
    PyFastFileType.tp_iter = (getiterfunc) PyFastFile_tp_iter;
    PyFastFileType.tp_iternext = (iternextfunc) PyFastFile_iternext;
    PyFastFileType.tp_dealloc = (destructor) PyFastFile_dealloc;
    ...
}

在这种情况下,

  1. tp_next() 是否返回了对linecache[0] 的拥有引用,因为它正在递增其Py_XINCREF
  2. 意思是,我的linecache[0] 缓存现在是借来的引用吗?
  3. 由于tp_next() 被多次调用,并且我多次返回相同的指针以增加其Py_XINCREF,这会导致双/三/数次释放吗?
  4. tp_next() 返回对象是否只有一个拥有的引用,这将导致双重/三重/多个?

相关:

  1. Py_INCREF/DECREF: When

【问题讨论】:

  • 你想要c++答案吗? shared_ptr 也许。

标签: python python-c-api


【解决方案1】:

您基本上需要一个对象的引用计数等于引用它的PyObject* 的数量。

  1. 是的 - 您将 PyObject* 返回到您的 Python 代码,因此您应该增加引用计数。

  2. 否 - 创建 linecache[0] 时,它的引用计数为 1,这表示 linecache 的所有权。多个地方可以“拥有”一个 Python 对象。

  3. 是的,您多次返回相同的指针;不,这不会导致多次释放。当引用计数达到 0 时,指针被释放。这将是当您中断对从 next 返回的值的所有引用时,以及当您丢失 linecache 中的引用时(当调用 PyFastFile_dealloc 时) .

  4. 最后一个问题没看懂,不过这里的代码基本是对的。


我在这里看到的一个问题是“linecache/谁拥有它”。如果它是一个全局变量,那么它最终可能会在多个 PyFastFile 对象之间共享,这可能是错误的。单个PyFastFile 的销毁将导致整个linecache 被释放,但您不会释放pop_backNULL 指针。

【讨论】:

    猜你喜欢
    • 2016-11-03
    • 2012-06-08
    • 2012-04-03
    • 2021-01-04
    • 2011-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多