【发布时间】:2012-01-03 06:36:06
【问题描述】:
我有一个 malloc() 并填充二维浮点数组的 C 函数。它“返回”该地址和数组的大小。签名是
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 函数分配的内存,而不是复制它。 (我刚刚在这个 StackOverflow 答案中找到了这个 PyBuffer_FromMemory 的东西: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
-
我也试过这个,但没有成功使用 ctypes。一个完整的扩展模块使这成为可能,但它们需要编写更多的工作。
标签: python c numpy free ctypes