【问题标题】:PyBuffer_New: Do I need to free manually?PyBuffer_New:我需要手动释放吗?
【发布时间】:2015-09-08 20:33:19
【问题描述】:

我正在寻找其他人代码中的内存泄漏。我发现:

def current(self):
    ...
    data = PyBuffer_New(buflen)
    PyObject_AsCharBuffer(data, &data_ptr, &buflen)
    ...
    return VideoFrame(data, self.frame_size, self.frame_mode,
                      timestamp=<double>self.frame.pts/<double>AV_TIME_BASE,
                      frameno=self.frame.display_picture_number)


cdef class VideoFrame:
    def __init__(self, data, size, mode, timestamp=0, frameno=0):
        self.data = data
        ...

在函数current() 中没有free 或类似的,在VideoFrame 中也没有。 VideoFrame 对象被删除时,PyBuffer 是否会自动释放?

【问题讨论】:

    标签: memory-leaks cython pybuffer


    【解决方案1】:

    答案是:“视情况而定;我们没有足够的代码来判断您的问题。”它取决于您告诉 Cython PyBuffer_New 返回的类型。我将给出两个简化的说明案例,希望您能够为您更复杂的案例解决。

    如果你告诉 Cython 它是一个 PyObject*,它对这种类型没有先天知识,也不会做任何事情来跟踪内存:

    # BAD - memory leak!
    
    cdef extern from "Python.h":
        ctypedef struct PyObject
        PyObject* PyBuffer_New(int size)
    
    def test():
        cdef int i
        for i in range(100000): # call lots of times to allocate lots of memory
            # (type of a is automatically inferred to be PyObject*
            # to match the function definition)
            a = PyBuffer_New(1000)
    

    并且为循环生成的代码看起来很像:

    for (__pyx_t_1 = 0; __pyx_t_1 < 1000; __pyx_t_1+=1) {
      __pyx_v_i = __pyx_t_1;
      __pyx_v_a = PyBuffer_New(1000);
    }
    

    即内存正在分配但从未释放。如果你运行test() 并查看任务管理器,你可以看到内存使用率上升而不是返回。

    或者,如果您告诉 Cython 它是一个 object,它可以让 Cython 像处理任何其他 Python 对象一样处理它,并正确管理引用计数:

    # Good - no memory leak
    
    cdef extern from "Python.h":
        object PyBuffer_New(int size)
    
    def test():
        cdef int i
        for i in range(100000):# call lots of times to allocate lots of memory
            a = PyBuffer_New(1000)
    

    然后为循环生成代码

    for (__pyx_t_1 = 0; __pyx_t_1 < 100000; __pyx_t_1+=1) {
      __pyx_v_i = __pyx_t_1;
      __pyx_t_2 = PyBuffer_New(1000); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 7; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
        __Pyx_GOTREF(__pyx_t_2);
        __Pyx_XDECREF_SET(__pyx_v_a, __pyx_t_2);
        __pyx_t_2 = 0;
    }
    

    注意DECREF,这将是释放对象的位置。如果您在此处运行test(),您不会看到内存使用量的长期跳跃。

    可以通过将cdef 用于变量来在这两种情况之间跳转(例如在VideoFrame 的定义中)。如果他们使用PyObject* 而不小心DECREFs 那么他们可能正在泄漏内存......

    【讨论】:

    • 谢谢!看来作者已经实现了“正确的”object PyBuffer_New(int size) 方式。我还看到 VideoFrame data 被定义为 cdef readonly object data 。是不是会泄露?
    • 刚刚发现__Pyx_GOTREF(__pyx_t_2);是在C文件中PyBuffer_New之后调用的。所以我想一切都正确实施了。
    • @P.R.我看不到任何我立即怀疑的东西(包括VideoFrame.data)。虽然显然很难从中分辨出来。查找内存泄漏的首选工具(至少在 Linux 上)是 Valgrind。不过我已经有一段时间没有真正使用它了,所以我无法给出任何真正的建议。
    猜你喜欢
    • 2013-07-31
    • 2011-03-17
    • 1970-01-01
    • 2010-09-08
    • 2012-01-22
    • 1970-01-01
    • 2011-03-01
    • 2011-06-13
    • 1970-01-01
    相关资源
    最近更新 更多