C# 请举例说明托管代码中的内存泄漏?

C# 请举例说明托管代码中的内存泄漏?,c#,C#,我在一次采访中被问到这个问题:众所周知,负责所有内存管理相关工作的垃圾收集器如何在C#as中出现内存泄漏问题?那怎么可能呢 来自:- 当在程序中分配内存并将其删除时,会发生内存泄漏 从未返回到操作系统,即使程序返回 不再使用内存。以下是内存泄漏的四种基本类型: 在手动管理的内存环境中:内存由指针动态分配和引用。在释放内存之前,指针将被擦除。删除指针后,无法再访问内存,因此无法释放内存 在动态管理的内存环境中:内存被释放但从未收集,因为对对象的引用仍然处于活动状态。因为对对象的引用仍然处于活动状

我在一次采访中被问到这个问题:众所周知,负责所有内存管理相关工作的垃圾收集器如何在C#as中出现内存泄漏问题?那怎么可能呢

来自:-

当在程序中分配内存并将其删除时,会发生内存泄漏 从未返回到操作系统,即使程序返回 不再使用内存。以下是内存泄漏的四种基本类型:

  • 在手动管理的内存环境中:内存由指针动态分配和引用。在释放内存之前,指针将被擦除。删除指针后,无法再访问内存,因此无法释放内存
  • 在动态管理的内存环境中:内存被释放但从未收集,因为对对象的引用仍然处于活动状态。因为对对象的引用仍然处于活动状态,所以垃圾收集器从不收集该内存。这可能发生在系统或程序设置的参考中
  • 在动态管理的内存环境中:垃圾收集器可以收集和释放内存,但不会将其返回到操作系统。当垃圾收集器无法将仍在使用的对象移动到内存的一部分并释放其余部分时,就会发生这种情况
  • 在任何内存环境中:当许多大型对象被声明并且永远不允许离开作用域时,可能会导致内存管理不善。因此,内存被使用,并且永远不会被释放
尽管此代码显然效率低下且不实用,但它旨在演示如果将对象添加到集合(例如将表添加到数据集集合),只要集合保持活动状态,对象就会保持活动状态。如果在程序的全局级别声明集合,并且在整个程序中声明对象并将其添加到该集合中,这意味着即使对象不再在范围内,对象仍保持活动状态,因为它们仍在被引用

您也可以检查此参考:-

上面的链接给出了一个非常好的结论

尽管.NET减少了对内存的关注, 您仍然必须注意应用程序对内存的使用,以便 确保其行为良好且高效仅仅因为 应用程序得到管理并不意味着你可以扔掉好的软件 窗外的工程实践,依靠GC来执行 魔法。

例如:

您的应用程序具有主窗体和静态变量popup[]collectionofpopus。 将所有应用程序弹出窗口对象存储到静态数组中,并且从不删除它们

因此,每个新弹出窗口都会占用内存,GC永远不会释放它

尝试阅读GC是如何工作的


这将解释一切。

可能有多种原因,但这里有一个:

考虑两类:

class A
{
  private B b;
}

class B
{
  private A a;
}

如果您为这些类中的每一个创建一个对象,并交叉链接它们,然后这两个对象都超出范围,那么您仍然可以在另一个类中链接到它们中的每一个。GC很难捕捉到这些类型的交叉链接,并且可能会继续认为这两个对象仍在使用。

当您实际上不再使用某个对象时,仅保留对该对象的引用是泄漏的好方法。尤其是当您将其存储在静态变量中时,这将创建一个在AppDomain生命周期内有效的引用,除非您显式地将其设置回null。如果这样一个引用存储在一个集合中,那么您可以得到一个真正的泄漏,该泄漏可能会使您的程序在OOM中崩溃。不平常

这样的漏洞可能很难找到。特别是事件可能很棘手,在订阅事件处理程序时,它们会让事件源对象添加对事件处理程序对象的引用。在C#代码中很难看到,因为在订阅事件时从未显式传递此消息。如果事件源对象存在很长时间,那么您可能会因为所有订阅服务器对象都保持被引用而遇到麻烦


棘手的问题确实需要内存分析器来诊断。

示例将是一个类
子类
包含
ClickEventHandler
方法,该方法订阅了另一个类
父类
的事件
ClickEvent

Child
类的
GC
将被阻止,直到
Parent
类超出范围。即使
Child
超出范围,它也不会被GC收集,直到
Parent
超出范围


在广播公司超出范围之前,GC不会收集订阅广播公司(
事件
)的所有此类订户

所以,这是一种单向关系

Broadcaster(ClickEvent) -> Subscribers(ClickEventHandler)

所有
ClickEventHandler
的GC将被阻止,直到
ClickEvent
超出范围

垃圾收集器在循环引用方面没有问题。如果A或B的实例没有可访问的引用,则将收集它们。NET GC不计算引用,而是确定可访问性。我认为许多组件仍然必须显式关闭/释放,以释放它们的资源。
Broadcaster(ClickEvent) -> Subscribers(ClickEventHandler)