2013-05-03 109 views
3

線程COM對象,我在一個線程中創建一個COM客戶端,並與該客戶進行的一些操作。每個線程都來自使用Python內置線程支持的socketserver模塊的服務器。內存泄漏和Python

當我加載並使用此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應該爲我照顧這個。任何幫助,將不勝感激。

+0

這可能不是完全相關,但嘗試使用線程池,而不是產生新的線程,但不定義類的例子,你的任何約束髮布。 – woozyking 2013-05-03 21:06:01

+0

TOM.Document是進程內還是進程外?你確定內存在「一段時間」之後沒有被釋放嗎?這可以發生在例如寫在技術與垃圾收集器COM對象(諸如.NET,雖然我懷疑TOM.Document寫入.NET) – 2013-05-03 21:41:03

+0

TOM.Document是進程。它不會在python.exe之外分叉另一個進程 – 2013-05-03 21:51:24

回答

5

事實證明這增加了內存,其實是由於.NET編寫的COM對象,不得不無關線程。 Here是任務管理器的詳細說明,它提供了有關.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() 
0

這裏是鏈接可以幫助你release COM in python win32

+0

謝謝你,這對確認腳本中沒有剩餘的COM引用非常有幫助,因爲pythoncom._GetInterfaceCount()= 0 – 2013-05-13 14:20:46

0

對我來說幫助(based)::

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()