我有一个C函数mallocs()并填充浮点数的二维数组。它“返回”该地址和数组的大小。签名是我可以强制让一个numpy ndarray拥有它的内存吗?
int get_array_c(float** addr, int* nrows, int* ncols);
我想从Python中调用它,所以我使用ctypes的。
import ctypes
mylib = ctypes.cdll.LoadLibrary('mylib.so')
get_array_c = mylib.get_array_c
我从来没想过如何用ctypes指定参数类型。我倾向于为我正在使用的每个C函数编写一个python包装器,并确保在包装器中正确地获取类型。浮点数组是一个列 - 主要顺序的矩阵,我想把它作为numpy.ndarray。但它非常大,所以我想使用C函数分配的内存,而不是复制它。 (我刚刚发现这个PyBuffer_FromMemory东西,在这个StackOverflow的答案:https://stackoverflow.com/a/4355701/3691)
buffer_from_memory = ctypes.pythonapi.PyBuffer_FromMemory
buffer_from_memory.restype = ctypes.py_object
import numpy
def get_array_py():
nrows = ctypes.c_int()
ncols = ctypes.c_int()
addr_ptr = ctypes.POINTER(ctypes.c_float)()
get_array_c(ctypes.byref(addr_ptr), ctypes.byref(nrows), ctypes.byref(ncols))
buf = buffer_from_memory(addr_ptr, 4 * nrows * ncols)
return numpy.ndarray((nrows, ncols), dtype=numpy.float32, order='F',
buffer=buf)
这似乎给我用正确的值的数组。但我很确定这是内存泄漏。
>>> a = get_array_py()
>>> a.flags.owndata
False
该阵列不拥有内存。很公平;默认情况下,当从缓冲区创建数组时,它不应该。但在这种情况下,它应该。当numpy数组被删除时,我真的很喜欢python为我释放缓冲区内存。看起来如果我可以强制owndata为True,那应该这样做,但是owndata不可设置。
解决方案不能令人满意:
使get_array_py的调用者()负责释放内存。这太烦人了;调用者应该能够像对待任何其他numpy数组一样对待这个numpy数组。
在get_array_py中将原始数组复制到一个新的numpy数组中(使用它自己的单独内存),删除第一个数组,然后释放get_array_py()中的内存。返回副本而不是原始数组。这很烦人,因为它应该是不必要的内存拷贝。
有没有办法做我想做的事?我不能修改C函数本身,尽管我可以在库中添加另一个C函数,如果这有帮助的话。
这听起来像一个痛苦的世界..我认为你是要[segfault hell](http://xkcd.com/371/) – wim 2012-01-03 07:27:17
我试过这个以及没有成功使用ctypes。完整的扩展模块使这成为可能,但他们更多的工作来写。 – 2012-02-01 20:20:25