Python ctypes.string_at释放行为

KSl*_*moe 3 python ctypes memory-management

我正在使用ctypes将某些C函数从DLL公开给Python脚本。其中一个函数返回一个动态调整大小的字符数组,我希望能够在Python中读取该数组的内容,而且还希望在完成处理后释放该数组的内存。

示例C代码:

...

#ifdef __cplusplus
extern "C"
{
#endif
    __declspec(dllexport) char * WINAPI get_str()
    {
        int str_len = ... // figure out how long it is gonna be and set it here
        char *ary = (char *)malloc(sizeof(char) * str_len);

        // populate the array
        ...

        ary[str_len - 1] = '\0';

        return ary;
    }

#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)

我构建了DLL,将其复制到将被找到的位置,然后具有以下Python代码:

import ctypes

my_dll = ctypes.WinDLL("MyDLLName.dll")

some_str = ctypes.string_at(my_dll.get_str())

print some_str
Run Code Online (Sandbox Code Playgroud)

这段代码都可以正常工作。我的问题是:由于ctypes.string_at在指定的内存位置创建了一个字符串,当some_str超出Python解释器的范围时,该内存将被垃圾回收,还是我需要手动释放它?

jsb*_*eno 5

string_at 在新的内存位置创建一个新的Python字符串,完全独立于调用它的内存位置。

Python或ctypes无法猜测您的本机代码返回了什么-就它而言,它只是一个数字(在这种情况下,它恰好是一个有效的指针)。

因此,经验法则是:如果您编写分配内存的C代码,则还应该编写等效的C代码来取消分配它-并使用Python代码调用从ctypes中释放C代码的代码。

对于像这样的快速脚本和示例,由于您知道它是一个简单的分配字符串,因此可以使用ctypes调用系统free函数直接从Python端释放它。

也就是说,将返回的指针存储在Python var:中(您可以将它指向或不指向正确的ctypes指针类型),然后在运行string_at之后使用:

pointer = my_dll.get_str()
some_str = ctypes.string_at(pointer)
# This is windows specific - 
# on Posix, one have to load "libc.so" and use "free" from there:
ctypes.cdll.msvcrt.free(pointer)
Run Code Online (Sandbox Code Playgroud)