内存泄漏了!

时间:2010-05-27 03:41:32

标签: c# memory-leaks

几周前,我遇到了与ContextMenuStrip相关的内存泄漏问题。这个问题得到解决。 See that question here

现在我遇到了与ToolStrip控件类似的问题。 与上一个问题一样,我正在创建大量UserControl并将它们添加到FlowLayoutPanel。每个控件在其构造函数中为自己创建一个ToolStrip。当从FlowLayoutPanel(对控件的唯一引用)中删除控件时,似乎没有释放ToolStrip的内存。

但是,当我注释掉创建ToolStrip的代码时,内存泄漏不会发生。

这是与前一个问题相同的问题 - 我需要将ToolStrip设置为null吗?我不知道这是怎么回事,因为这次控件正在创建条带本身,并且所有按钮事件等都在其中处理。因此,当控件不再被引用时,不应该一切都是GC吗?

编辑: 至于评论,我不明白的事情原来是我从一个面板和一些标签“制作”我自己的工具条。标签用作按钮。这种方式没有发生内存泄漏。

我唯一改变的是使用适当的ToolStrip和适当的按钮代替面板,但所有事件处理程序都以相同的方式连接。那为什么现在泄漏记忆呢?

EDIT2: 我正准备发布我的代码,但重读了Dave链接的问题。事实证明这是ToolStrip的UserPreferenceChangedEvent问题。如果我将ToolStrip.Visible属性设置为false,则不会发生内存泄漏!

现在,我可以在Dispose方法中执行此操作吗?如果是这样的话?我尝试复制一些代码,但我得到一个编译警告:“MyToolStrip.Dispose()”隐藏继承的成员'System.ComponentModel.Component.Dispose()“ 我只是不明白IDisposable接口。

2 个答案:

答案 0 :(得分:2)

95%的情况下,您正在注册事件处理程序,而不是在清除控件集合时取消注册它们。那将是我看的第一个地方

(我认为朱丽叶的评论应该是一个答案)

答案 1 :(得分:0)

正式在C#内存泄漏不存在。在没有人再使用它之后,内存会被释放一段时间。

然而,在某些情况下,这为时已晚。特别是如果您的对象使用稀缺资源,您可能希望该对象更早地“破坏”。

每当你看到一个类实现了System.IDisposable时,该类的设计者认为在你不再需要它时尽快处理对象是明智的。这样就可以在垃圾收集器执行之前释放资源。

如果您不处理对象,垃圾收集器将为您完成...最终。但是如果你想早点释放你的资源,请在你不再需要该对象时立即调用Dispose。

您正在谈论用户控件。 U用户控件是一个控件和控件实现System.IDisposable。所以你应该打电话给dispose。如果不这样做,则需要一些时间才能释放资源。

在不需要时尽快确保对象是Disposed的最简单方法是using语句:

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

myFile被正确刷新/关闭/处置/最终确定,即使您有异常或因任何原因退出使用块:return / break,无论如何。

实现System.IDisposable通常使用模式完成。这种模式包括创建一个额外的Dispose(bool)函数,该函数由Dispose和Destructor函数调用。 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;
         }
     }

     ...
 }

我个人从未需要使用布尔处理。正式说它:

  

如果要发布托管和非托管资源,则为true; false仅释放非托管资源。

但我想不出为什么我不想发布托管资源。

如果你收到Dispose()隐藏另一个Dispose()的警告,你可能继承了实现System.IDisposable的东西。在这种情况下,你不需要析构函数和Dispose(),你只需要Dispose(bool)。在MSDN中查找,你会发现你可以覆盖它。