繁体   English   中英

Python ctypes 'c_char_p' 内存泄漏

[英]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库,因此所有数字都转换为mpzmpq 我使用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_tmpq_t对象的空间。

问题出在这一行:

res = ctypes.c_char_p(a.value)

这将创建的副本a.value ,并设置resc_char_p指向副本。 但是Python不会对ctypes指针做内存管理,所以副本会泄露!

如果将以上行替换为以下内容,则应修复泄漏:

res = bytes(memoryview(a.value))

这也会创建一个副本,但res将是一个真正的 Python 对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM