简体   繁体   English

在.NET等托管环境中是否可能发生内存泄漏?

[英]Are memory leaks possible in managed environments like .NET?

In C++ it is easily possible to have a permanent memory leak - just allocate memory and don't release it: 在C ++中,很容易产生永久性内存泄漏 - 只需分配内存而不释放内存:

new char; //permanent memory leak guaranteed

and that memory stays allocated for the lifetime of the heap (usually the same as program runtime duration). 并且该内存在堆的生命周期内保持分配(通常与程序运行时的持续时间相同)。

Is the same (a case that will lead to a specific unreferenced object never been released while memory management mechanisms are working properly) possible in a C# program? 在C#程序中,是否可能(在内存管理机制正常工作的情况下会导致特定的未引用对象被释放)?

I've carefully read this question and answers to it and it mentions some cases which lead to getting higher memory consumption than expected or IMO rather extreme cases like deadlocking the finalizer thread, but can a permanent leak be formed in a C# program with normally functioning memory management? 我仔细阅读了这个问题并给出了答案,它提到了一些导致内存消耗高于预期的情况或IMO相当极端的情况,比如终结器线程死锁,但是在正常运行的C#程序中会形成永久性泄漏内存管理?

It depends on how you define a memory leak. 这取决于您如何定义内存泄漏。 In an unmanaged language, we typically think of a memory leak as a situation where memory has been allocated, and no references to it exist, so we are unable to free it. 在非托管语言中,我们通常将内存泄漏视为已分配内存的情况,并且不存在对它的引用,因此我们无法释放它。

That kind of leaks are pretty much impossible to create in .NET (unless you call out into unmanaged code, or unless there's a bug in the runtime). 在.NET中创建这种泄漏几乎是不可能的(除非你调用非托管代码,或者除非运行时有错误)。

However, you can get another "weaker" form of leaks: when a reference to the memory does exist (so it is still possible to find and reset the reference, allowing the GC to free the memory normally), but you thought it didn't, so you assumed the object being referenced would get GC'ed. 但是,你可以得到泄漏的另一种“弱”的形式:当对内存的引用存在的(所以还是有可能找到并重新设置参考,允许GC来释放正常的内存),但你认为它没” t,所以你假设被引用的对象会得到GC。 That can easily lead to unbounded growth in memory consumption, as you're piling up references to objects that are no longer used, but which can't be garbage collected because they're still referenced somewhere in your app. 这很容易导致内存消耗的无限增长,因为你正在堆积对不再使用的对象的引用,但是它们不能被垃圾收集,因为它们仍然在应用程序的某处被引用。

So what is typically considered a memory leak in .NET is simply a situation where you forgot that you have a reference to an object (for example because you failed to unsubscribe from an event). 因此,在.NET中通常被认为是内存泄漏的情况只是您忘记了对对象的引用(例如,因为您未能取消订阅事件)。 But the reference exists, and if you remember about it, you can clear it and the leak will go away. 但是参考文献存在,如果你记得它,你可以清除它,泄漏就会消失。

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

It's not exactly a memory leak, but if you're communicating with hardware drivers directly (ie not through a properly-written .net extension of a set of drivers) then it's fairly possible to put the hardware into a state where, although there may or may not be an actual memory leak in your code, you can no longer access the hardware without rebooting it or the PC... 这不是一个内存泄漏,但如果你直接与硬件驱动程序通信(即不通过一组驱动程序的正确编写.net扩展),那么很可能将硬件置于一个状态,尽管可能或者可能不是代码中的实际内存泄漏,您无法再重新启动硬件或PC而无法访问硬件...

Not sure if this is a useful answer to your question, but I felt it was worth mentioning. 不确定这是否是对你的问题有用的答案,但我觉得值得一提。

GC usually delay the collection of unreachable memory to some later time when an analysis of the references show that the memory is unreachable. 当对引用的分析显示内存不可达时,GC通常会将无法访问的内存的收集延迟到以后的某个时间。 (In some restricted cases, the compiler may help the GC and warn it that a memory zone is unreachable when it become so.) (在某些受限制的情况下,编译器可能会帮助GC并警告它在内存区域变为无法访问时。)

Depending on the GC algorithm, unreachable memory is detected as soon as a collection cycle is ran, or it may stay undetected for a certain number of collection cycles (generational GC show this behavior for instance). 根据GC算法,一旦运行收集周期就会检测到无法访问的内存,或者它可能在一定数量的收集周期内未被检测到(例如,分代GC显示此行为)。 Some techniques even have blind spots which are never collected (use of reference counted pointer for instance) -- some deny them the name of GC algorithm, they are probably unsuitable in general purpose context. 有些技术甚至有从未收集的盲点(例如使用引用计数指针) - 有些人否认它们是GC算法的名称,它们可能不适用于通用上下文。

Proving that a specific zone will be reclaimed will depend on the algorithm and on the memory allocation pattern. 证明将回收特定区域取决于算法和内存分配模式。 For simple algorithm like mark and sweep, it is easy to give a bound (says till the next collection cycle), for more complex algorithms the matter is more complex (under a scheme which use a dynamic number of generations, the conditions in which a full collection is done are not meaningful to someone not familiar with the detail of the algorithm and the precise heuristics used) 对于像标记和扫描这样的简单算法,很容易给出一个约束(直到下一个收集周期),对于更复杂的算法,问题更复杂(在使用动态数代的方案下,条件是完全收集对于不熟悉算法细节和使用的精确启发式的人没有意义

A simple answer is that classic memory leaks are impossible in GC environments, as classically a memory leak is leaked because, as an unreferenced block theres no way for the software to find it to clean it up. 一个简单的答案是经典的内存泄漏在GC环境中是不可能的,因为经典的内存泄漏被泄露,因为作为一个未引用的块,软件无法找到它来清理它。

On the other hand, a memory leak is any situation where the memory usage of a program has unbounded growth. 另一方面,内存泄漏是程序的内存使用量无限增长的任何情况。 This definition is useful when analyzing how software might fail when run as a service (where services are expected to run, perhaps for months at a time). 在分析软件作为服务运行时可能会失败的情况时(定义服务运行,可能一次持续数月),此定义非常有用。

As such, any growable data structure that continues to hold onto references onto unneeded objects could cause service software to effectively fail because of address space exhaustion. 因此,任何可持续保留对不需要的对象的引用的可扩展数据结构都可能导致服务软件因地址空间耗尽而有效地失败。

Easiest memory leak: 最简单的内存泄漏:

public static class StaticStuff
{
    public static event Action SomeStaticEvent;
}

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

instances of Listener will never be collected. 永远不会收集监听器的实例。

If we define memory leak as a condition where a memory that can be used for creating objects, cannot be used or a memory that can be released does not then 如果我们将内存泄漏定义为可以用于创建对象的内存,不能使用的内存或者可以释放的内存那么

Memory leaks can happen in: 内存泄漏可能发生在:

  • Events in WPF where weak events need to be used. WPF中需要使用弱事件的事件。 This especially can happens in Attached Properties . 这尤其可以在附加属性中发生。
  • Large objects 大物件

Large Object Heap Fragmentation 大对象堆碎片

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM