内存泄漏在C#中

当你确定所有的句柄,实现IDispose东西都被丢弃时,在托管系统中是否有可能泄漏内存?

会不会有一些变数被忽略的情况?


事件处理程序是非常明显的内存泄漏的常见来源。 如果您从object2订阅object1上的事件,然后执行object2.Dispose()并假装它不存在(并从您的代码中删除所有引用),则object1的事件中存在一个隐式引用,该引用将阻止object2存在垃圾收集。

MyType object2 = new MyType();

// ...
object1.SomeEvent += object2.myEventHandler;
// ...

// Should call this
// object1.SomeEvent -= object2.myEventHandler;

object2.Dispose();

这是泄露的常见情况 - 忘记轻松取消订阅事件。 当然,如果object1被收集,object2也会被收集,但是直到那时才会收集。


我不认为C ++风格的内存泄漏是可能的。 垃圾收集器应该考虑这些。 即使对象不再被使用,也可以创建一个聚合对象引用的静态对象。 像这样的东西:

public static class SomethingFactory
{
    private static List<Something> listOfSomethings = new List<Something>();

    public static Something CreateSomething()
    {
        var something = new Something();
        listOfSomethings.Add(something);
        return something;
    }
}

这是一个明显愚蠢的例子,但它将等同于托管的运行时内存泄漏。


正如其他人指出的那样,只要内存管理器中没有实际的错误,那些不使用非托管资源的类就不会泄漏内存。

你在.NET中看到的不是内存泄漏,而是永远不会处理的对象。 只要垃圾收集器可以在对象图上找到它,对象就不会被丢弃。 所以如果任何地方的任何活物都有对象的引用,它就不会被处置。

事件注册是实现这一目标的好方法。 如果一个对象注册了一个事件,那么它注册的任何对象都有一个引用,并且即使你消除了对该对象的所有其他引用,直到它注销(或注册的对象变得无法访问),它也会保持活动状态。

所以你必须小心那些在你不知情的情况下注册静态事件的对象。 例如, ToolStrip一个非常漂亮的功能是,如果您更改显示主题,它将自动重新显示新主题。 它通过注册静态SystemEvents.UserPreferenceChanged事件来实现这个漂亮的功能。 当您更改Windows主题时,会引发该事件,并且正在侦听该事件的所有ToolStrip对象都会收到通知,说明有新主题。

好吧,假设你决定在你的表单上丢弃一个ToolStrip

private void DiscardMyToolstrip()
{
    Controls.Remove("MyToolStrip");
}

你现在有一个永远不会死的ToolStrip 。 即使它不在您的表单上,每当用户更改主题时,Windows都会尽职尽责地告诉其他不存在的ToolStrip 。 每次垃圾收集器运行时,它都会认为“我不能丢弃该对象, UserPreferenceChanged事件正在使用它”。

这不是内存泄漏。 但它可能是。

像这样的事情使内存分析器非常宝贵。 运行一个内存分析器,你会说“这很奇怪,堆上似乎有一万个ToolStrip对象,即使我的表单上只有一个,这是怎么发生的?”

哦,如果你想知道为什么有些人认为属性设置器是邪恶的:为了让ToolStripUserPreferenceChanged事件中取消注册,请将其Visible属性设置为false

链接地址: http://www.djcxy.com/p/57027.html

上一篇: Memory Leak in C#

下一篇: PHP Download Script Creates Unreadable ZIP File on Mac