2012-11-28 49 views
0

我的課程使用COM資源,並且從IDisposable繼承了它。並清理非託管資源我有Dispose()方法,我在調用Marshall.ReleaseCOMObject()方法...所以我的問題是我們是否還需要一個Destructor方法(Finalizer)?釋放COM資源?當我使用finalzier方法並調用Marshal或Dispose時,我將得到一個RCW錯誤,並且當我移除終結器方法時,我不會再遇到RCW錯誤但是如果我查看一個內存分析器,我可以看到非託管資源內存不斷增加eveery時間我打開它有這個COM資源的形式...所以看起來喜歡它沒有清理它?那麼在C#應用程序中清理COM資源的正確方法是什麼?我們是否需要.NET中的Finalizer方法?

我將用一些代碼示例更新這個問題。

謝謝。

private MyCOMobject theCOMobject = null; 

static SuppressFieldCntrlr() 
{ 
    new SomeCalss(); 
} 


private bool disposed = false; 

public void Dispose() 
{ 
    Dispose(true); 
    GC.SuppressFinalize(this); 
} 

private void Dispose(bool disposing) 
{ 
    if (!this.disposed) 
    { 
     if (disposing) 
     { 
      //nothing in here, is it just for Managed Resources? 
     } 

     Marshal.ReleaseComObject(this); 
     MethodFoo(false); 

     disposed = true; 
    } 
} 
+2

只是想補充一句:如果你在你的類中添加了終結器,你的類將自動處理有點不同。 gc的第一個突破,你的對象不是直接收集,而是放在終結器隊列中。並在下一次運行中,將被召集和收集。但是,當然這隻會發生,如果你的對象不再被任何引用,否則你可能只是有一個普通的內存泄漏,我猜是你的問題。 – dowhilefor

+0

@dowhilefor:intresting信息。我不知道排隊。簡單的內存泄漏聽起來很正確。你能否詳細說明如何解決並找到它?這裏是關於這個原始問題,尚未答覆:http://stackoverflow.com/questions/13609098/writing-the-correct-idisposable-implementation-for-classes-with-com-objects/13609416#13609416謝謝 – Bohn

+1

好吧我最好的建議是:使用內存分析器來查找泄漏:)如果prefere redgates螞蟻內存分析器,但我敢肯定,有很多在那裏。一些調查建議:請記住,事件持有很強的參考。事實上,檢查你是否使用單身人士,檢查所有在某一點上持有一個參考的物體,並且比你的泄漏級別活得更長。 – dowhilefor

回答

0

如果我們有非託管資源,強烈建議使用終結器。 在這種情況下:

~ClassName 
{ 
    Dispose(false); 
} 
+0

我打算提到這一點,但你說過一些例外情況。這是你的終結者看起來像什麼? – Alan

+0

@Alan:是的,這正是我一開始就有的。該代碼的原始問題是沒有回答在這裏:http://stackoverflow.com/questions/13609098/writing-the-correct-idisposable-implementation-for-classes-with-com-objects/13609416#13609416 – Bohn

2

如果該類不直接擁有的非託管資源,你知道,沒有派生類都不會直接擁有的非託管資源(例如,因爲你的類是密封的,你的類是內部),那麼你不需要一個終結器。

就我個人而言,即使不是絕對必要,我也會使用終結器實現標準模式。主要是爲了最不讓人驚訝的原則,並且因爲其他人可能決定將其封裝或允許派生類將來使用非託管資源。

還要注意的是一個COM對象是管理資源,所以你應該叫ReleaseComObject的處置時是正確的:

private void Dispose(bool disposing) 
{ 
    if (!this.disposed) 
    { 
     if (disposing) 
     { 
      // Dispose managed resources 
      Marshal.ReleaseComObject(this); 
     } 
     // If you directly own unmanaged resources, they'd be freed here 

     disposed = true; 
    } 
} 
+0

我會假設如果一個類沒有明確設計來處理非託管資源,那麼派生類也不應該直接持有任何一類。相反,如果一個派生類需要擁有一個非託管資源,那麼該資源應該封裝在一個小的(可能是私有的)類中,該類設計用於確保其清理,並且派生類應該將該資源存儲在該較小類的對象中。資源持有者對象需要一個終結器,但派生類不需要。 .net'IDisposable'模式允許派生類做某事*他們不應該這樣做。* – supercat

2

你封裝管理的對象,而不是一個非託管的一個。您沒有P/invoke'd來獲取Win32文件句柄或設備上下文或類似的東西;相反,您已經獲得了對託管對象的引用 - RCW。您應該將您的電話Marshal.ReleaseComObject放在Dispose(bool)方法的if (disposing)部分。

RCW本身將有一個終結器,它將處理實際COM對象的簿記,所以如果您尚未在需要最終確定的位置調用ReleaseComObject,COM對象將被刪除垃圾收集器。

+0

好的,謝謝,我現在應該刪除Finalizer方法嗎?將現在嘗試它,並且還會查看內存分析器結果。我的恐懼是Unmanaged部分越來越大,沒有終結者。但是,我確定現在會嘗試它)。 – Bohn

+0

從你所展示的內容來看,你的班級沒有任何內容需要完成,所以我會刪除它。 – prprcupofcoffee

相關問題