use*_*318 3 c python memory memory-leaks
我有一个 python 模块,它调用 C 编写的 DLL 来编码 XML 字符串。一旦函数返回编码字符串,它就无法取消分配在此步骤中分配的内存。具体来说:
编码MyString = ctypes.create_string_buffer(4096)
CallEncodingFuncInDLL(encodeMyString,InputXML)
我已经查看了this、this和this ,并且还尝试调用 thegc.collect但也许由于该对象已在外部 DLL 中分配,因此 python gc 没有它的任何记录并且无法删除它。但由于代码不断调用编码函数,它不断分配内存,最终导致 python 进程崩溃。有没有办法分析内存使用情况?
由于您没有提供有关 DLL 的任何信息,因此这必然是相当模糊的,但是 \xe2\x80\xa6
\n\nPython 无法跟踪它不知道的外部事物分配的内存。怎么可能呢?该内存可以是 DLL 常量段的一部分,或者用mmap或分配VirtualAlloc分配,或者是较大对象的一部分,或者 DLL 可能只是期望它处于活动状态以供自己使用。
任何具有分配和返回新对象的函数的 DLL 都必须具有释放该对象的函数。例如,如果CallEncodingFuncInDLL返回一个您负责的新对象,则会有一个类似的函数DestroyEncodedThingInDLL接受这样的对象并释放它。
那么,什么时候调用这个函数呢?
\n\n让我们退后一步,让这个问题变得更加具体。假设该函数是普通的旧函数strdup,因此您调用来释放内存的函数是free. 对于何时致电,您有两种选择free。不,我不知道你为什么要打电话strdup从 Python 调用,但这是一个最简单的示例,所以让我们假设它不是无用的。
第一个选项是致电strdup,立即将返回值转换为本机 Python 对象并释放它,之后不必担心:
newbuf = libc.strdup(mybuf)\ns = newbuf.value\nlibc.free(newbuf)\n# now use s, which is just a Python bytes object, so it\'s GC-able\nRun Code Online (Sandbox Code Playgroud)\n\n或者,更好的是,将其包装起来,以便使用自定义的自动操作restype:
def convert_and_free_char_p(char_p):\n try:\n return char_p.value\n finally:\n libc.free(char_p)\nlibc.strdup.restype = convert_and_free_char_p\n\ns = libc.strdup(mybuf)\n# now use s\nRun Code Online (Sandbox Code Playgroud)\n\n但是有些对象无法如此轻松地转换为本机 Python 对象\xe2\x80\x94,或者可以,但这样做并不是很有用,因为您需要不断将它们传递回 DLL。在这种情况下,在使用完毕之前您无法清理它。
\n\n做到这一点的最好方法是将不透明的值包装在一个类中,在close或__exit__或__del__或任何看起来合适的地方释放它。一种很好的方法是使用@contextmanager:
@contextlib.contextmanager\ndef freeing(value):\n try:\n yield value\n finally:\n libc.free(value)\nRun Code Online (Sandbox Code Playgroud)\n\n所以:
\n\nnewbuf = libc.strdup(mybuf)\nwith freeing(newbuf):\n do_stuff(newbuf)\n do_more_stuff(newbuf)\n# automatically freed before you get here\n# (or even if you don\'t, because of an exception/return/etc.)\nRun Code Online (Sandbox Code Playgroud)\n\n或者:
\n\n@contextlib.contextmanager\ndef strduping(buf):\n value = libc.strdup(buf)\n try:\n yield value\n finally:\n libc.free(value)\nRun Code Online (Sandbox Code Playgroud)\n\n现在:
\n\nwith strduping(mybuf) as newbuf:\n do_stuff(newbuf)\n do_more_stuff(newbuf)\n# again, automatically freed here\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
1317 次 |
| 最近记录: |