2010-05-27 58 views
0

幾個星期前,我遇到了與ContextMenuStrip有關的內存泄漏問題。這個問題已經解決了。 See that question here內存泄漏,再次!

現在我遇到了ToolStrip控件的類似問題。 和前面的問題一樣,我創建了大量的UserControl並將它們添加到FlowLayoutPanel中。每個控件都在其構造函數中爲其自身創建一個ToolStrip。當從FlowLayoutPanel(對控件的唯一引用)中刪除控件時,似乎ToolStrip的內存未被釋放。

但是,當我註釋掉創建ToolStrip的代碼時,內存泄漏不會發生。

這和前面的問題一樣 - 我需要將ToolStrip設置爲null?我不明白這是怎麼回事,因爲這時控制器正在創建條帶本身,並且所有的按鈕事件都在其中進行處理。所以當控件不再被引用時,不應該把所有東西都GC'd?

編輯: 至於評論,我不明白的事情是我原來是「製造」自己的工具條了一個面板和一些標籤。標籤被用作按鈕。這種方式沒有發生內存泄漏。

我唯一改變的是使用合適的ToolStrip和適當的按鈕來代替面板,但所有事件處理程序都以相同的方式進行連線。那爲什麼它現在正在泄漏記憶?

編輯2: 我剛剛發佈我的代碼,但重讀了戴夫鏈接到的問題。事實證明,這是ToolStrip的UserPreferenceChangedEvent問題。如果我將ToolStrip.Visible屬性設置爲false,則內存泄漏不會發生!

現在,我可以在Dispose方法中執行此操作嗎?如果是這樣如何?我試圖複製一些代碼,但我得到了一個編譯警告:「MyToolStrip.Dispose()'隱藏繼承成員'System.ComponentModel.Component.Dispose()」 我只是不理解IDisposable接口。

+5

95%的時間,你註冊事件處理程序,而不是清除你的控件集合時取消註冊它們。那將是我看的第一個地方。 – Juliet 2010-05-27 03:48:30

+0

不知道這個問題是否有幫助,但我發現它很有趣:http://stackoverflow.com/questions/620733/memory-leak-in-c – Dave 2010-05-27 03:53:19

回答

2

95%的時間,你註冊事件處理程序,而不是清除你的控件集合時取消註冊它們。這將是第一個地方,我看

(我以爲朱麗葉的評論當之無愧地成爲一個答案)

+0

我剛剛添加代碼,以確保所有事件處理程序已取消訂閱之前刪除FlowLayoutPanel的控件和內存使用量仍在上升。 不幸的是我對Memory Profiler的試用已過期。我只是不知道發生了什麼。我還沒有嘗試使用IDisposable的知識(怪我讀了關於它:)。但我不明白爲什麼在這種情況下是必要的。 正如我所說的,它工作正常(沒有內存泄漏),直到我切換到使用ToolStrip,即使沒有取消訂閱事件。 – Dave 2010-05-27 05:27:06

0

正式在C#中的內存泄漏是不存在的。內存釋放一段時間後,沒有人再使用它。

但是對於某些情況來說這太遲了。特別是如果你的對象使用稀缺資源,你可能希望對象提前「破壞」。

每當你看到一個類實現了System.IDisposable時,那麼這個類的設計者認爲一旦你不再需要它的時候就立即處理對象是明智的。這樣資源就可以在垃圾收集器完成之前釋放出來。

如果你不處理對象,垃圾收集器會爲你做...最終。但是,如果您希望更早釋放資源,請注意只要不再需要該對象,就立即調用Dispose。

您正在討論用戶控件。 U用戶控件是一個控件和控件實現System.IDisposable。所以你應該打電話處置。如果你不這樣做,在釋放資源之前需要一些時間。

最簡單的方法,以確保對象只要沒有必要佈置有using語句:

using (var myFile = File.Create(...)) 
{ 
    myFile.Write(...) 
    ... 
} 

MYFILE是正確的沖洗/關閉/處理/敲定,即使你有例外或獲取出於任何原因使用塊:返回/中斷,無論如何。

實現System.IDisposable通常使用模式完成。這個模式由創建一個由函數Dispose和Destructor調用的額外的Dispose(bool)函數組成。布爾參數告訴你是否要處置。

class TextWriter : System.IDisposable 
{ 
    private StreamWriter writer = null; 

    public TextWriter(string fileName) 
    { 
     this.writer = StreamWriter(fileName); 
    } 

    ~TextWriter() // destructor 
    { 
     this.Dispose(false); // false: I am not disposing 
    } 

    public void Dispose() 
    { 
     this.Dispose(true); // true: I am disposing 
     GC.SuppressFinalize(this); 
     // tell the garbage collector that this object doesn't need to be 
     // finalized (destructed) anymore 
    } 

    private void Dispose(bool dispose) 
    { 
     if (this.writer != null) 
     { 
      this.writer.Dispose(); 
      this.writer = null; 
     } 
    } 

    ... 
} 

個人而言,我從來沒有需要使用布爾優化配置。官方這樣說的:

真正釋放託管和非託管資源;假只釋放非託管資源。

但我想不出爲什麼我不想釋放託管資源。

如果您得到Dispose()隱藏另一個Dispose()的警告,那麼您可能繼承了實現System.IDisposable的某些東西。在這種情況下,你不需要析構函數和Dispose(),你只需要Dispose(bool)。在MSDN中查看它,你會發現你可以覆蓋它。