【发布时间】:2015-11-02 12:52:42
【问题描述】:
我正在编写一个 Python 类,它将包装一个包含 C 结构的 C 模块。我正在使用 Cython 语言(Python 和 C 的超集语言)。 C 结构在构造函数中是 malloc 的,并且包含一个我想在 Python 中使用的数组。该数组将在 Python 中表示为 NumPy 数组,但我不想将值复制到其中。我想将 NumPy 数组直接链接到 malloc 的内存。对于这个任务,我使用NumPy Array API,特别是这个函数:
PyObject*PyArray_SimpleNewFromData(int nd, npy_intp* dims, int typenum, void* data)
我设法在 Cython 中使用此代码将 NumPy 数组绑定到 C 结构的数组,只要 NumPy 数组和 MultimediaParams 对象具有相同的生命周期,它就可以正常工作:
cdef class MultimediaParams:
def __init__(self, **kwargs):
self._mm_np = < mm_np *> malloc(sizeof(mm_np))
#some code...
def as_ndarray(self): #TODO: what if self deallocated but numpy array still exists(segfault?)
cdef numpy.npy_intp shape[1]
cdef int arr_size = sizeof(self._mm_np[0].n2) / sizeof(self._mm_np[0].n2[0])
shape[0] = < numpy.npy_intp > arr_size
cdef numpy.ndarray ndarray
ndarray = numpy.PyArray_SimpleNewFromData(1, shape, numpy.NPY_DOUBLE, self._mm_np[0].n2)
return ndarray
def __dealloc__(self):
free(self._mm_np)
如您所见,该类有其 __dealloc__ 方法,该方法将处理在 C 中分配的内存,并在没有对 MultimediaParams 实例的引用时释放它。
在这种绑定中,NumPy 不拥有数组的内存。
问题:当MultimediaParams对象被释放,数组的内存被释放时,NumPy对象仍然指向刚刚释放的内存。当 NumPy 对象尝试访问/修改已释放的内存时,这将导致段错误。
只要有一个 NumPy 对象在使用其内存,我如何确保 MultimediaParams 对象不会被释放?
据我了解,我需要做的就是让 NumPy 对象引用一个 MultimediaParams 实例,从该实例中获取内存指向。
我尝试使用ndarray.base = <PyObject*>self,以便 NumPy 知道它的基对象,这应该添加对 MultimediaParams 实例的另一个引用,并且只要 NumPy 数组还活着,它就不会被释放。这一行导致我的测试失败,因为 NumPy 数组的内容变成了垃圾。
澄清:NumPy 数组不拥有 C 数组内存的所有权,我不希望它拥有。我希望 MultimediaParams 负责释放C 结构(包含数组数据),但只要 NumPy 对象还活着,就不要这样做。
有什么建议吗?
【问题讨论】:
-
@DavidW:它看起来不像是重复的。强制内存所有权可能会导致双重
free(),这是不好的。 OP 的问题是ndarray.base = <PyObject*>selfdoesn't work -
如果你在
.base分配之后Py_INCREF(self)会发生什么? -
@J.F.Sebastian 我在想 OP 真正想要解决的问题是确保内存与数组具有相同的生命周期(并试图通过将其绑定到 @987654343 的实例来解决它@)。但是他们可能有其他原因来链接这两个实例 - 在这种情况下我错了,它不是重复的......
-
@DavidW:
PyArray_ENABLEFLAGS(ndarray, np.NPY_OWNDATA)如何让MultimediaParams实例保持活动状态?
标签: python c arrays numpy cython