使用外部C DLL时Python中的内存泄漏

2024-09-30 22:18:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个python模块,它调用一个C编写的DLL来编码XML字符串。一旦函数返回编码字符串,它将无法取消分配在此步骤中分配的内存。具体来说:

编码字符串=ctypes.create_string_缓冲区(4096个)

CallEncodingFuncInDLL(encodeMyString,InputXML)

我已经看过了thisthisthis,还尝试过调用gc.collect,但可能因为对象是在外部DLL中分配的,python gc没有它的任何记录,也无法删除它。但是由于代码一直在调用encoding函数,它继续分配内存,最终python进程崩溃。有没有一种方法可以分析这种内存使用情况?在


Tags: 模块函数内存字符串编码stringcreate步骤
1条回答
网友
1楼 · 发布于 2024-09-30 22:18:54

因为你没有给出任何关于DLL的信息,这将必然是相当模糊的,但是

Python无法跟踪它不知道的外部事物分配的内存。怎么可能?该内存可以是DLL的常量段的一部分,或者分配给mmap或{},或者是一个更大对象的一部分,或者DLL可能只是希望它能为自己的使用而活。在

任何具有分配和返回新对象的函数的DLL都必须有一个释放该对象的函数。例如,如果CallEncodingFuncInDLL返回一个您负责的新对象,则会有一个类似DestroyEncodedThingInDLL的函数获取这样一个对象并释放它。在

你什么时候调用这个函数?在


让我们退一步,让这更具体。假设这个函数是普通的strdup,因此您调用的释放内存的函数是free。何时调用free有两个选择。不,我不知道为什么要从Python调用strdup,但这是一个最简单的示例,所以让我们假设它不是无用的。在


第一个选项是调用strdup,立即将返回的值转换为本机Python对象并释放它,之后不必担心它:

newbuf = libc.strdup(mybuf)
s = newbuf.value
libc.free(newbuf)
# now use s, which is just a Python bytes object, so it's GC-able

或者,更好的方法是,通过使用自定义的^{}可调用函数将其自动打包:

^{pr2}$

但是有些对象不能很容易地转换为本机Python对象,或者可以转换为本机Python对象,但是这样做并不是很有用,因为您需要不断地将它们传递回DLL。那样的话,你不能把它清理干净。在

最好的方法是将这个不透明值包装在一个类中,该类在close或{}或{}或任何合适的地方释放它。一种很好的方法是使用^{}

@contextlib.contextmanager
def freeing(value):
    try:
        yield value
    finally:
        libc.free(value)

所以:

newbuf = libc.strdup(mybuf)
with freeing(newbuf):
    do_stuff(newbuf)
    do_more_stuff(newbuf)
# automatically freed before you get here
# (or even if you don't, because of an exception/return/etc.)

或者:

@contextlib.contextmanager
def strduping(buf):
    value = libc.strdup(buf)
    try:
        yield value
    finally:
        libc.free(value)

现在:

with strduping(mybuf) as newbuf:
    do_stuff(newbuf)
    do_more_stuff(newbuf)
# again, automatically freed here

相关问题 更多 >