当您编写数千行 .NET 代码时,您要注意什么以避免内存泄漏?我是预防检查的忠实拥护者,关于这一点有一个著名的例子是使用“StringBuilder”来组合字符串而不是“String1+String2”,那么您的编码经验还有什么?
提前感谢您分享您的想法。
当您编写数千行 .NET 代码时,您要注意什么以避免内存泄漏?我是预防检查的忠实拥护者,关于这一点有一个著名的例子是使用“StringBuilder”来组合字符串而不是“String1+String2”,那么您的编码经验还有什么?
提前感谢您分享您的想法。
事件。始终取消订阅事件,这是 .NET 最容易泄露的一个特性。
订阅事件的意思是“在你还活着的时候通知并持有我”,而不是“在我还活着的时候通知我”。未能取消订阅事件通常会导致大量悬挂对象,尤其是在 UI 中。
使用后将根引用设置为 null。
更多信息在这里:如果我们忘记清空根引用,则 GC 将无法尽快有效地释放内存,从而导致应用程序占用更大的内存。问题可能很微妙,例如在进行远程调用(如数据库查询或对 Web 服务的调用)之前创建临时对象的大图的方法。如果在远程调用期间发生垃圾收集,则整个图都被标记为可达并且不会被收集。这变得更加昂贵,因为在收藏中幸存下来的物品会被提升到下一代,这可能会导致中年危机。
确保始终处置 IDisposable 对象。此外,尝试始终使用“使用(...)”块来声明一次性对象。
尽可能地意识到你所做的每一件事的复杂性,并考虑每一种情况,而不是依赖教条。例如,还要注意使用 StringBuilder 并不总是连接字符串的正确方法:)
在可能的情况下,尝试流式传输数据而不是缓冲数据 - 当涉及到 LINQ to Objects 时,您需要在这里小心,了解哪些操作符缓冲和哪个流(以及哪些操作都使用不同的序列)。
(这些都不是真正的内存“泄漏” - 但我正在考虑可以快速使用比预期更多的内存的地方。)
不完全是内存泄漏,但总是让我明白的一件事:
使用它们后始终关闭您的 SQL 连接。
每个 DataTable.NewRow() 都必须有一个匹配的 DaraTable.Rows.Add(...)。
如果使用 COM 互操作,请在使用完 COM 对象后使用 Marshal.ReleaseComObject 来释放 Runtime Callable Wrapper (RCW)。
此外,如果您的 COM 对象具有返回另一个 COM 对象的属性或方法,请注意始终将其分配给变量并在之后释放它。
即这将泄漏GetFirstChild接收到的对象:
string name = myBigComObject.GetFirstChild().Name;
使用它:
ChildComObject firstChild = myBigComObject.GetFirstChild()
string name = firstChild.Name;
Marshal.ReleaseComObject(firstChild);
something.someEvent += new EventHandler(memoryhog.someMethod);
[...]
something.someEvent += new EventHandler(memoryhog.someMethod);
[...]
something.someEvent -= new EventHandler(memoryhog.someMethod);
如果您错过了从对象中取消所有事件处理程序的操作,那么实现该事件处理程序的对象将在该对象的整个生命周期内停留在内存中。
托管 DirectX 库有这样的错误,这会导致大量内存泄漏。
特定于 .NET Compact Framework:您必须明确处理所有与图形相关的对象(Graphics、Pen、SolidBrush、Bitmap),否则它们会在内存中徘徊(当您使用低内存设备时效果不佳)。