.net NET中的内存泄漏

.net NET中的内存泄漏,.net,optimization,memory-leaks,.net,Optimization,Memory Leaks,在.NET中,有哪些可能的方法可以获取内存泄漏 我知道两个: 未正确取消注册 不在Windows窗体中处理动态子控件: 例如: // Causes Leaks Label label = new Label(); this.Controls.Add(label); this.Controls.Remove(label); // Correct Code Label label = new Label(); this.Controls.Add(label); this

在.NET中,有哪些可能的方法可以获取内存泄漏

我知道两个:

  • 未正确取消注册
  • 不在Windows窗体中处理动态子控件:
  • 例如:

    // Causes Leaks  
    Label label = new Label();  
    this.Controls.Add(label);  
    this.Controls.Remove(label);  
    
    // Correct Code  
    Label label = new Label();  
    this.Controls.Add(label);  
    this.Controls.Remove(label);  
    label.Dispose();
    
    更新:想法是列出不太明显的常见陷阱(如上述)。通常的概念是,由于垃圾收集器,内存泄漏不是一个大问题。不像以前在C++中使用。
    很好的讨论,伙计们,但让我澄清一下。。。根据定义,如果.NET中没有对对象的引用,它将在某个时候被垃圾收集。因此,这不是导致内存泄漏的方法

    在托管环境中,如果您无意中引用任何您不知道的对象(我的问题中有两个例子),我会认为它是内存泄漏。


    那么,发生这种内存泄漏的各种可能方式是什么?

    无法提供全面的列表。。。这很像是问“你怎么会淋湿?”

    也就是说,请确保对实现IDisposable的所有对象调用Dispose(),并确保对使用任何类型的非托管资源的任何类型实现IDisposable


    时不时地,在代码库上运行类似于FxCop的程序来帮助您执行该规则——您会惊讶地发现一些一次性对象在应用程序框架中被埋藏得有多深。

    您是在谈论意外的内存使用还是实际的泄漏?您列出的两个案例并不完全是泄漏;在这种情况下,物体停留的时间比预期的要长

    换句话说,它们是那些称之为内存泄漏的人不知道或忘记的引用

    编辑:或者它们是垃圾收集器或非托管代码中的实际bug


    编辑2:考虑这一点的另一种方法是始终确保适当释放对对象的外部引用。“外部”是指您无法控制的代码。发生这种情况的任何情况都可能导致内存“泄漏”。

    在非托管语言中可能导致内存泄漏的许多事情仍然可能导致托管语言中的内存泄漏。例如,可能导致内存泄漏


    但正如格雷格和丹尼所说,没有全面的清单。任何可能导致在内存使用寿命后保留内存的操作都可能导致内存泄漏。

    每次调用IDisposable都是最简单的开始,也是获取代码库中所有低挂内存泄漏结果的有效方法。然而,这并不总是足够的。例如,了解托管代码在运行时如何生成以及何时生成也很重要,而且一旦将程序集加载到应用程序域中,它们就永远不会被卸载,这会增加应用程序占用空间。

    这并不会真正导致泄漏,只会让GC做更多的工作:

    // slows GC
    Label label = new Label();  
    this.Controls.Add(label);  
    this.Controls.Remove(label);  
    
    // better  
    Label label = new Label();  
    this.Controls.Add(label);  
    this.Controls.Remove(label);  
    label.Dispose();
    
    // best
    using( Label label = new Label() )
    { 
        this.Controls.Add(label);  
        this.Controls.Remove(label);  
    }
    
    在.Net这样的托管环境中,让一次性组件像这样到处乱放从来都不是什么大问题——这是托管的一个重要意义

    当然,你会让你的应用程序慢下来。但您不会为其他任何事情留下混乱。

    Finalize(或来自Finalizer的Dispose调用)方法中的异常会阻止正确处置非托管资源。
    常见的一种情况是,程序员假设将处理什么顺序的对象,并尝试释放已处理的对等对象,导致异常,而Finalize/Dispose from Finalize方法的其余部分未被调用。

    阻止终结器线程。在取消阻止终结器线程之前,不会对其他对象进行垃圾收集。因此,使用的内存量将不断增长


    进一步阅读:

    死锁线程永远不会释放根。显然,你可以说僵局带来了一个更大的问题

    死锁的终结器线程将阻止所有剩余的终结器运行,从而阻止所有可终结对象被回收(因为它们仍由freachable列表作为根)

    在多CPU机器上,您可以比终结器线程运行终结器更快地创建可终结对象。只要这种情况持续下去,你就会“泄漏”内存。这种情况不大可能在野外发生,但很容易繁殖

    大型对象堆未压缩,因此可能会通过碎片泄漏内存


    有许多对象必须手动释放。例如,远程处理没有租约和程序集的对象(必须卸载AppDomain)。

    直接设置GridControl.DataSource属性,而不使用BindingSource类()的实例

    这导致我的应用程序中出现漏洞,我花了很长时间使用探查器进行追踪,最终我发现了Microsoft响应的错误报告:

    有趣的是,在BindingSource类的文档中,Microsoft试图将其作为一个经过深思熟虑的合法类,但我认为他们创建它只是为了解决有关货币管理器和将数据绑定到网格控件的基本漏洞

    请注意这一点,我敢打赌,由于这一点,绝对有大量泄漏的应用程序

  • 保留对不再需要的对象的引用

  • 关于其他注释-确保调用Dispose的一种方法是使用。。。当代码结构允许时。

    为防止.NET内存泄漏:

    1) 每当创建具有“IDisposable”接口的对象时,请使用“using”构造(或“try finally”构造)

    2) 如果类创建线程或将对象添加到静态或长寿命集合,则将类设置为“IDisposable”。记住,“事件”是一个集合


    下面是一篇关于的短文。

    有一件事让我非常意外,那就是:

    Region oldClip = graphics.Clip;
    using (Region newClip = new Region(...))
    {
        graphics.Clip = newClip;
        // draw something
        graphics.Clip = oldClip;
    }
    
    内存泄漏在哪里?对,你也应该处理掉
    oldClip
    !因为
    图形