我是不是需要释放从通过 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 函数返回的内存?的主要内容,如果未能解决你的问题,请参考以下文章

Python cffi学习

如何使用 cffi-lua 向/从 C 函数传递 Lua 表

在 Python CFFI 中声明包含 time_t 字段的结构

您是不是必须释放传递给 Emscripten 中导出的 C 函数的字符串?

如何配置 python cffi 库以使用 mingw?

如何使用 cffi 在 C 中嵌入一个返回字符串的 Python 函数?