内存泄漏在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
对象,即使我的表单上只有一个,这是怎么发生的?”
哦,如果你想知道为什么有些人认为属性设置器是邪恶的:为了让ToolStrip
从UserPreferenceChanged
事件中取消注册,请将其Visible
属性设置为false
。
上一篇: Memory Leak in C#