在像.net这样的托管环境中是否可能发生内存泄漏?

本文关键字:是否 可能发生 内存 泄漏 环境 net 在像 | 更新日期: 2023-09-27 17:50:12

在c++中很容易发生永久性内存泄漏—只需分配内存而不释放它:

new char; //permanent memory leak guaranteed

并且该内存在堆的生命周期内保持分配(通常与程序运行时持续时间相同)。

是相同的(一种情况下,将导致一个特定的未引用的对象从未被释放,而内存管理机制正常工作)可能在c#程序?

我仔细阅读了这个问题并回答了它,它提到了一些导致内存消耗比预期更高的情况,或者像死锁终结器线程这样的极端情况,但是在具有正常功能的内存管理的c#程序中可以形成永久泄漏吗?

在像.net这样的托管环境中是否可能发生内存泄漏?

这取决于您如何定义内存泄漏。在非托管语言中,我们通常认为内存泄漏是这样一种情况:内存已经分配,但不存在对它的引用,因此我们无法释放它。

这种泄漏几乎不可能在。net中创建(除非您调用非托管代码,或者除非运行时存在错误)。

然而,您可以获得另一种"较弱"形式的泄漏:当对内存的引用确实存在时(因此仍然有可能找到并重置引用,从而允许GC正常释放内存),但您认为不存在,因此您假设被引用的对象将被GC'ed。这很容易导致内存消耗的无限增长,因为你正在堆积对不再使用的对象的引用,但这些对象无法被垃圾收集,因为它们仍然在你的应用程序的某个地方被引用。 因此,在. net中,通常被认为是内存泄漏的情况仅仅是您忘记了对对象的引用(例如,因为您未能取消订阅事件)。但是参考文献是存在的,如果你记得它,你可以清除它,泄漏就会消失。

如果你愿意,你可以在。net中编写非托管代码,你已经用不安全关键字包围了你的代码块,所以如果你正在编写不安全的代码,你是不是回到了自己管理内存的问题,如果没有得到内存泄漏?

这并不完全是一个内存泄漏,但如果你直接与硬件驱动程序通信(即不是通过一组驱动程序的正确编写的。net扩展),那么它是相当有可能把硬件进入一个状态,虽然可能有或可能没有实际的内存泄漏在你的代码,你不能再访问硬件不重启它或PC…

不确定这是否是对你问题的有用答案,但我觉得值得一提。

GC通常将不可达内存的收集延迟到稍后的某个时间,当对引用的分析显示内存不可达时。(在某些受限的情况下,编译器可能会帮助GC,并在内存区域不可达时警告它。)

根据GC算法,一旦运行收集周期就会检测到不可达内存,或者在一定数量的收集周期内保持未检测到内存(例如,分代GC显示这种行为)。有些技术甚至有盲点,这些盲点永远不会被收集(例如使用引用计数指针)——有些拒绝使用GC算法的名称,它们可能不适合通用上下文中。

证明一个特定的区域将被回收将取决于算法和内存分配模式。标记和清扫等简单的算法,很容易给人一种束缚(说到未来收集周期),对于更复杂的算法问题是更复杂的(使用动态的一代又一代的计划,完成一个完整的集合的条件是没有意义的人不熟悉的细节所使用的精确算法和启发式)

一个简单的答案是,经典的GC环境中的内存泄漏是不可能的,典型的内存泄漏是因为,作为一个未引用的块,软件没有办法找到它来清理它。

另一方面,内存泄漏是指程序的内存使用无限制增长的任何情况。这个定义在分析软件作为服务运行时可能出现的故障时很有用(服务预计会运行,可能一次运行几个月)。

因此,任何持续持有对不需要对象的引用的可增长数据结构都可能导致服务软件由于地址空间耗尽而失败。

简单的内存泄漏:

public static class StaticStuff
{
    public static event Action SomeStaticEvent;
}
public class Listener
{
   public Listener() {
      StaticStuff.SomeStaticEvent+=DoSomething;
   }
   void DoSomething() {}
}

如果我们将内存泄漏定义为可用于创建对象的内存不能使用或可以释放的内存不能使用的情况,那么

内存泄漏可能发生在:

  • 需要使用弱事件的WPF事件。这尤其可能发生在附加属性中。
  • 大对象

大对象堆碎片

http://msdn.microsoft.com/en-us/magazine/cc534993.aspx