我是不是需要释放从通过 CFFI 调用的 C 函数返回的内存?
Posted
技术标签:
【中文标题】我是不是需要释放从通过 CFFI 调用的 C 函数返回的内存?【英文标题】:Do I need to free memory returned from a C function called via CFFI?我是否需要释放从通过 CFFI 调用的 C 函数返回的内存? 【发布时间】:2018-04-15 06:41:44 【问题描述】:我有这个示例代码,它有一个函数 text()
返回一个新分配的字符串:
ffi_test = FFI()
ffi_test.set_source('_test', '''
char* test() return strdup("hello world");
''')
ffi_test.cdef('''
char* test();
void free(void *);
''')
ffi_test.compile(verbose=True)
这很好用:
In [1]: from _test import ffi, lib
In [2]: x = lib.test()
In [3]: ffi.string(x)
Out[3]: b'hello world'
In [4]: lib.free(x)
但是,我在文档中找不到任何内容,无论我是否真的需要手动 free()
返回的字符串,如果 CFFI 在指针返回到 Python 代码后立即获得该指针的所有权。
另外,如果我确实需要手动 free()
它,我需要在我的 cdefs 中公开 free()
还是 CFFI 提供了一些更好的方法?
【问题讨论】:
当对象的“所有权”从一个软件组件传递到另一个软件组件时,新所有者将负责释放内存。因为这就是“所有权”的含义。 【参考方案1】:来自Working with pointers, structures and arrays 上的文档,引用正确的部分:
在 C 中任何会返回指针、数组或结构类型的操作都会为您提供一个新的 cdata 对象。 与“原始”不同,这些新的 cdata 对象没有所有权
因此您必须释放它,它无法承担所有权: 在 C 中,有许多函数返回一个指针,该指针指向内存中的常量字符串,例如,它不仅不是动态分配的,也不是分配的,或者根本是可修改的。释放这些将是非常错误的。
对于free
,文档中说如下:
另一种方法是声明和调用 C 的 malloc() 和 free() 函数,或一些变体,如 mmap() 和 munmap()。然后,您可以准确控制何时分配和释放内存。例如,将这两行添加到您现有的 ffibuilder.cdef() 中:
void *malloc(size_t size); void free(void *ptr);
由于 正确 C 标准库 free
用于 strdup
返回的指针非常重要,因此您不能依靠 CFFI 神奇地做正确的事情,而是正如您所怀疑的那样,你应该暴露free()
。如果需要,您还可以按照 Barmar 的建议使用 gc
注册自动清理:
x = ffi.gc(x, lib.free)
【讨论】:
谢谢!那是我错过的文档中的一部分。现在只剩下第二部分了——即我是否需要像上面那样公开free()
,或者如果CFFI自动这样做(lib.free
不存在,但如果我不在我的cdef中手动公开它)跨度>
如果你知道对象是用malloc()
动态分配的,你可以用ffi.gc()
注册lib.free
来回收它。以上是关于我是不是需要释放从通过 CFFI 调用的 C 函数返回的内存?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 cffi-lua 向/从 C 函数传递 Lua 表
在 Python CFFI 中声明包含 time_t 字段的结构