[英]Python ctypes 'c_char_p' memory leak
我正在开发一个用于密码学的 Python 库。 我想通过使用 GMP 用 C++ 编写主要类来优化我的库。 我编写了我的 C++ 类并编写了extern
方法来使用主要的算术运算:加法、减法等......这些方法将结果返回为 char* 以避免转换问题。 我构建了库的 DLL,并在带有 ctypes 的 Python 包装器中声明了方法。 我注意到在每次有大量数字的算术运算之后,内存呈指数增长。 我一直在寻找我的 C++ 实现中的问题,但由于 C++ 垃圾收集器,没有问题。 我正在寻找一个可能的解决方案,所以我发现我必须实现一个 C++ 方法来释放由 DLL 创建的字符串的内存。 所以我写了这个简单的方法:
extern "C" {
__declspec(dllexport) void free_memory(char * n)
{
free(n);
}
...
}
我在 Python 包装器中实现了此代码以释放 DLL 分配的内存:
import os
import ctypes
DIR_PATH = os.path.dirname(os.path.realpath(__file__))
NUMERIC = ctypes.CDLL(DIR_PATH + "/numeric.dll")
...
NUMERIC.free_memory.argtypes = [ctypes.c_void_p]
NUMERIC.free_memory.restype = None
def void_cast(n):
a = ctypes.cast(n, ctypes.c_char_p)
res = ctypes.c_char_p(a.value)
NUMERIC.free_memory(a)
return res
因此,与res = ctypes.c_char_p (a.value)
创建一个新的变量,它不再指向a
。 这样我使用DLL方法正确删除a
,但我仍然有内存泄漏问题。 就好像 Python 垃圾收集器没有正确c_char_p
类型的字符串的内存c_char_p
。 在之前的实现中,我只使用了 Python 和gmpy2
库,因此所有数字都转换为mpz
或mpq
。 我使用memory_profiler
包测试了内存消耗。 我创建了 40 个投影点类型的对象,定义在椭圆曲线上,我计算了i*P
的乘积, i
从 1 到gmpy2
总共使用了大约 70MB。 相反,将 ctypes 与 C++ 中的类一起使用,内存消耗上升到 1.5GB。 很明显有问题,特别是当只有处理算术运算的基类发生变化时。 如何在没有内存泄漏问题的情况下正确释放内存? 我举了一个用于计算算术运算的extern
方法的例子,但我已经检查过问题仅在于通过free_memory
函数正确释放内存并重新分配字符串,以便 Python 的垃圾收集器在需要时释放字符串。
extern "C" {
__declspec(dllexport) const char* rat_add(const char * n, const char * m)
{
return (RationalNum(n) + RationalNum(m)).getValue();
}
}
提前致谢,祝您有美好的一天。
PS:显然在 C++ 中,我正确地实现了析构函数方法来释放创建的mpz_t
和mpq_t
对象的空间。
问题出在这一行:
res = ctypes.c_char_p(a.value)
这将创建的副本a.value
,并设置res
的c_char_p
指向副本。 但是Python不会对ctypes
指针做内存管理,所以副本会泄露!
如果将以上行替换为以下内容,则应修复泄漏:
res = bytes(memoryview(a.value))
这也会创建一个副本,但res
将是一个真正的 Python 对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.