在托管系统中,当您确保所有句柄(实现 IDispose
接口的对象)都已释放时,是否可能出现内存泄漏?
是否存在一些变量被遗漏的情况?
在托管系统中,当您确保所有句柄(实现 IDispose
接口的对象)都已释放时,是否可能出现内存泄漏?
是否存在一些变量被遗漏的情况?
事件处理程序是非常普遍的隐蔽内存泄漏来源。如果你在对象1上订阅了来自对象2的事件,然后执行object2.Dispose()并假装它不存在(从代码中删除所有引用),那么在对象1的事件中有一个隐含的引用将防止对象2被垃圾回收。
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;
}
}
那是一个显然很愚蠢的例子,但它相当于托管运行时的内存泄漏。
部分,我仍然看不到在每个
while`迭代之后回收的内存。难道只是等待GC进行收集吗? - Ternaryprivate void DiscardMyToolstrip()
{
Controls.Remove("MyToolStrip");
}
你现在有一个永远不会消失的ToolStrip
。即使它不再在你的表单上,每次用户更改主题时,Windows都会如实地告诉这个看起来不存在的ToolStrip
。每次垃圾回收器运行时,它都会认为:“我不能扔掉那个对象,因为UserPreferenceChanged
事件正在使用它。”
这不是内存泄漏。但也可以说是。
像这样的问题使得内存分析器非常有价值。运行内存分析器,你会发现“奇怪的是,似乎在堆中有一万个ToolStrip
对象,尽管我的表单上只有一个。这是怎么回事?”
哦,如果你想知道为什么有些人认为属性设置器很邪恶:要让ToolStrip
从UserPreferenceChanged
事件注销,将其Visible
属性设置为false
。
委托可能会导致令人费解的内存泄漏。
每当从实例方法创建委托时,一个指向该实例的引用就被存储“在”该委托中。
此外,如果将多个委托合并成多路广播委托,则将具有对众多对象的引用的大块引用保留,只要该多路广播委托在某个地方被使用,这些对象就不会被垃圾回收。
Control.AllowDrop
属性(用于启用拖放)。如果将AllowDrop
设置为“true”,CLR仍将通过System.Windows.Forms.DropTarget
保留您的控件。要解决这个问题,请确保当您不再需要它时,您的Control
的AllowDrop
属性设置为false
,CLR会处理余下的事情。如前所述,保留引用会导致随着时间的推移内存使用量增加。一种容易陷入这种情况的方法是使用事件。如果您有一个长期存在的对象,其中包含一些其他对象监听的事件,如果这些监听器从未被移除,那么长寿命对象上的事件将使得这些其他实例在不再需要它们后仍然保持活动状态。
反射发射是另一个潜在的泄漏源,例如内置对象反序列化器和花哨的SOAP / XML客户端。至少在框架的早期版本中,依赖AppDomains中生成的代码从未被卸载...
DynamicMethod
也会在AppDomain中持久存在。 - Konrad Rudolph