4

我正在一个线程中创建一个 COM 客户端并使用该客户端执行多个操作。每个线程都是从使用 Python 模块的服务器产生的,该socketserver模块具有内置的线程支持。

当我加载和使用这个 COM 对象时,python.exe 的内存使用量会出现预期峰值。对于 10 个并发线程,内存使用量峰值约为 500Mb。但是,当操作完成并且 COM 对象明显释放时,该进程使用的内存比以前增加了 50Mb。如果我随后使用同一台服务器生成 10 个额外的线程,那么在这些 COM 对象关闭后,python.exe 将额外使用 13Mb。最终,每 10 个额外的并发线程在完成后会增加大约 6Mb。当我结束整个 python.exe 进程时,所有内存都被释放。

我已经简化了以下代码来模仿 socketserver 的使用方式threadding,问题是完全相同的。

import win32com.client
import threading
import pythoncom

def CreateTom():
    pythoncom.CoInitialize()
    tom = win32com.client.Dispatch("TOM.Document")
    tom.Dataset.Load("FileName")
    tom.Clear()
    pythoncom.CoUninitialize()

for i in range(50):
    t = threading.Thread(target = CreateTom)
    t.daemon = False
    t.start()

我知道我不太可能在特定的 COM 库(它是市场研究中使用的 IBM 产品,称为 TablesObjectModel)获得任何支持。但是,我想知道是否有任何事情,任何事情,我可以做些什么来释放这个记忆。我已经阅读了 COM 中的公寓,但听起来 pythoncom.CoInitialize 应该为我处理这个问题。任何帮助,将不胜感激。

4

3 回答 3

6

事实证明,内存的增加实际上是由于用 .NET 编写的 COM 对象,与线程无关。是任务管理器的详细描述,它提供了有关 .NET 应用程序的内存使用情况的误导性信息。为了解决这个问题,我在我的代码中添加了以下内容,我已经准备好了。希望其他人在开始努力寻找代码中的内存泄漏之前阅读此响应。

from win32process import SetProcessWorkingSetSize
from win32api import GetCurrentProcessId, OpenProcess
from win32con import PROCESS_ALL_ACCESS

import win32com.client
import threading
import pythoncom

def CreateTom():
    pythoncom.CoInitialize()
    tom = win32com.client.Dispatch("TOM.Document")
    tom.Dataset.Load("FileName")
    tom.Clear()
    pythoncom.CoUninitialize()
    SetProcessWorkingSetSize(handle,-1,-1) #Releases memory after every use

pid = GetCurrentProcessId()
handle = OpenProcess(PROCESS_ALL_ACCESS, True, pid)

for i in range(50):
    t = threading.Thread(target = CreateTom)
    t.daemon = False
    t.start()
于 2013-05-17T20:08:37.520 回答
0

这里的链接可以帮助你在 python win32 中释放 COM

于 2013-05-13T04:22:38.447 回答
0

对我来说它有帮助(基于)::

from comtypes.automation import IDispatch
from ctypes import c_void_p, cast, POINTER, byref

def release_reference(self, obj):
    logger.debug("release com object")
    oleobj = obj._oleobj_
    addr = int(repr(oleobj).split()[-1][2:-1], 16)

    pointer = POINTER(IDispatch)()
    cast(byref(pointer), POINTER(c_void_p))[0] = addr
    pointer.Release()
于 2017-05-03T09:15:10.460 回答