2009-01-06 64 views
1

我有一個IIS 2.0下的ASP.NET 2.0應用程序,其功能爲 將一些數據導出到名爲HFM(Oracle Hyperion財務管理)的軟件中。 要執行導出,.net應用程序使用基於HFM客戶端提供的COM對象的API(客戶端安裝在與服務器等相同的機器上).NET強制COM對象發佈

我的問題是API提供了方法連接到HFM服務器,但不要斷開連接。
該文檔說,要斷開連接,應用程序必須在創建的每個COM對象上調用方法Marshal.ReleaseComObject()。 但是,執行了很多複雜的操作,我無法釋放所有創建的對象。
所以我的應用程序不會斷開連接。

我注意到,當我替換ASP.NET應用程序的dll文件(似乎重新啓動由.NET實例化的對象)時,應用程序會自動斷開連接。

我打了幾次撥打:

GC.Collect(); 
GC.WaitForPendingFinalizers(); 

但問題仍然存在。 我正在尋找一種方法來確保創建任何對象,甚至COM對象都被釋放。 我試過Marshal.FinalReleaseComObject()但它不是更好。

當我在該部分放置一個lock()時,該部分總是最多有一個用戶,所以我甚至可以使用硬核技術來釋放COM對象。

有沒有辦法知道哪個對象或者至少沒有被釋放的對象的類型?

感謝您的幫助。

回答

1

但是有很多複雜的操作執行,我無法釋放所有創建的對象。

這是你的問題。

您正在尋找一個簡單的出路。但是你正在使用COM。您獲得的唯一簡單方法是關閉流程/應用程序域。

+0

在徹底的分析和過程簡化之後,你說得對,我們注意到一些對象沒有正確釋放。 這是問題的原因。 – 2010-07-14 14:27:37

2

你可以把一個通用的包裝類型實現IDisposable圍繞每個COM實例嗎?

然後你可以的Dispose方法中調用Marshal.FinalReleaseComObject(或環上Marshal.ReleaseComObject的檢查引用計數),並且只能通過使用聲明引用您的包裝類型實例化COM對象。

做這個包裝技巧的另一個好處是你可以使用CLR profiler來檢查你的類型實例還沒有被處置,從而回答你的最後一個問題。

1

調用Marshal.ReleaseComObject或Marshal後,將變量設置爲Null/Nothing是非常重要的。FinalReleaseComObject。

Dim cn As ADODB.Connection 
cn = New ADODB.Connection 
cn.Open(_cnnstr) 
cn.Execute(sbDML.ToString) 
cn.Close() 
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cn) 
cn = Nothing '!!!IMPORTANT!!! - Do not remove, MUST be explicitly called! 

此外,我還注意到,創造另一種方法有助於避免與處理本地COM對象(變量放在棧上)的問題。例如,如果您有一個方法可以完成所有工作,請將其包裝在另一個方法中,然後添加對垃圾回收的調用,然後調用封裝器。

Public Sub MainMethod 
    '... 
    Marshal.FinalReleaseComObject(foo) 
    foo = Nothing '!!!IMPORTANT!!! - Do not remove, MUST be explicitly called! 
End Sub 

Public Sub WrapperMethod 
    Call MainMethod 
    GC.Collect() 
End Sub 

相信額外的調用,與創建的局部變量的另外堆疊的,強制的對象被完全收集更快,導致要完全釋放COM對象。

我一直在追蹤這種模式幾年,現在我沒有任何問題。