如何解决 Python 中使用的供应商 DLL 中的内存泄漏问题?
How to workaround a memory leak in a vendor's DLL being used in Python?
我通过使用 Python 的 ctypes 模块加载他们的库,将供应商的 C API 用于一个商业软件。
部署我编写的软件后,我发现供应商的库会根据其 API.[=13] 中某个函数的调用次数,以一致且可预测的方式泄漏内存=]
我什至在不使用堆分配的 C 程序中复制了泄漏。
我就这个问题联系了供应商,他们说他们正在解决这个问题,但我可能无法期望在下一版本的软件之前得到修复。
我有过在调用泄漏函数达到一定阈值后重新加载供应商的 dll 的想法,但这并没有释放泄漏的内存。
我发现我可以像这样强制卸载库:
_ctypes.FreeLibrary(vendor_dll._handle)
这会释放内存,但会导致解释器在使用供应商的 API 几分钟后随机崩溃。
我在描述我的情况的 Python 错误跟踪器中发现了这个问题:
https://bugs.python.org/issue14597
看来,如果仍然有对库的开放引用,强制卸载将不可避免地使 Python 解释器崩溃。
最坏的情况,我想我可以在单独的进程中加载供应商的库,使用多处理队列代理请求,并设置看门狗以在解释器死机时重新创建进程。
有没有更好的方法来解决这个问题?
最后,我通过在单独的进程中加载供应商的库并通过 Pyro4 访问它来解决问题,如下所示:
class LibraryWorker(multiprocessing.Process):
def __init__(self):
super().__init__()
def run(self):
self.library = ctypes.windll.LoadLibrary(
'vendor_library.dll')
Pyro4.serveSimple(
{self, 'library'},
ns=False)
def lib_func(self):
res = self.library.func()
return res
修改旧代码以不在两个进程之间传递 ctypes 指针需要一些额外的工作,但它确实有效。
在单独的进程中加载库后,我可以跟踪内存使用情况。当它变得太高时,我可以终止并重新创建进程以释放内存。
我通过使用 Python 的 ctypes 模块加载他们的库,将供应商的 C API 用于一个商业软件。
部署我编写的软件后,我发现供应商的库会根据其 API.[=13] 中某个函数的调用次数,以一致且可预测的方式泄漏内存=]
我什至在不使用堆分配的 C 程序中复制了泄漏。
我就这个问题联系了供应商,他们说他们正在解决这个问题,但我可能无法期望在下一版本的软件之前得到修复。
我有过在调用泄漏函数达到一定阈值后重新加载供应商的 dll 的想法,但这并没有释放泄漏的内存。
我发现我可以像这样强制卸载库:
_ctypes.FreeLibrary(vendor_dll._handle)
这会释放内存,但会导致解释器在使用供应商的 API 几分钟后随机崩溃。
我在描述我的情况的 Python 错误跟踪器中发现了这个问题: https://bugs.python.org/issue14597
看来,如果仍然有对库的开放引用,强制卸载将不可避免地使 Python 解释器崩溃。
最坏的情况,我想我可以在单独的进程中加载供应商的库,使用多处理队列代理请求,并设置看门狗以在解释器死机时重新创建进程。
有没有更好的方法来解决这个问题?
最后,我通过在单独的进程中加载供应商的库并通过 Pyro4 访问它来解决问题,如下所示:
class LibraryWorker(multiprocessing.Process):
def __init__(self):
super().__init__()
def run(self):
self.library = ctypes.windll.LoadLibrary(
'vendor_library.dll')
Pyro4.serveSimple(
{self, 'library'},
ns=False)
def lib_func(self):
res = self.library.func()
return res
修改旧代码以不在两个进程之间传递 ctypes 指针需要一些额外的工作,但它确实有效。
在单独的进程中加载库后,我可以跟踪内存使用情况。当它变得太高时,我可以终止并重新创建进程以释放内存。