C#中的内存泄漏

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/620733/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 10:36:03  来源:igfitidea点击:

Memory Leak in C#

c#.netmemory-leaksgarbage-collectionmanaged

提问by Joan Venge

Is it ever possible in a managed system to leak memory when you make sure that all handles, things that implement IDisposeare disposed?

当您确保所有句柄和实现的东西都被释放时,在托管系统中是否有可能泄漏内存IDispose

Would there be cases where some variables are left out?

会不会有遗漏某些变量的情况?

回答by Michael Meadows

I don't think C++ style memory leaks are possible. The garbage collector should account for those. It is possible to create a static object that aggregates object references even though the objects are never used again. Something like this:

我认为 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;
    }
}

That's an obviously stupid example, but it would be the equivalent of a managed runtime memory leak.

这显然是一个愚蠢的例子,但它相当于托管运行时内存泄漏。

回答by Kevin Laity

Once all the references to an object are gone, the garbage collector will free that object on it's next pass. I wouldn't say it's impossible to leak memory but it's fairly difficult, in order to leak you'd have to have a reference to an object sitting around without realizing it.

一旦对一个对象的所有引用都消失了,垃圾收集器将在下一次传递时释放该对象。我不会说泄漏内存是不可能的,但它相当困难,为了泄漏你必须有一个对坐在周围的对象的引用而没有意识到它。

For example if you instantiate objects into a list and then forget to remove them from the list when you're done AND forget to dispose them.

例如,如果您将对象实例化到一个列表中,然后在完成后忘记将它们从列表中删除并忘记处理它们。

回答by Bob The Janitor

While it is possible that something in the framework has a leak, more then likely you have something that isn't being being disposed of properly or something is blocking the GC from disposing of it, IIS would be a prime candidate for this.

虽然框架中的某些内容可能存在泄漏,但更有可能的是您的某些内容未正确处理或某些内容阻止 GC 处理它,IIS 将是此问题的主要候选者。

Just remember that not everything in .NET is fully managed code, COM interop, file io like file streams, DB requests, images, etc.

请记住,并非 .NET 中的所有内容都是完全托管的代码、COM 互操作、文件 io(如文件流)、DB 请求、图像等。

A problem we had a while ago (.net 2.0 on IIS 6) was that we would create an image and then dispose of it but IIS wouldn't release the memory for a while.

不久前我们遇到的一个问题(IIS 6 上的 .net 2.0)是我们将创建一个映像然后处理它,但 IIS 暂时不会释放内存。

回答by Ben S

It's possible to have leaks if unmanaged resources do not get cleaned properly. Classes which implement IDisposablecan leak.

如果未正确清理非托管资源,则可能会出现泄漏。实现IDisposable 的类可能会泄漏。

However, regular object references do not require explicit memory management the way lower level languages do.

但是,常规对象引用不需要像低级语言那样进行显式内存管理。

回答by Michael Trausch

The only leaks (other than bugs in the runtime which may be present, though not terribly likely due to garbage collection) are going to be for native resources. If you P/Invoke into a native library which opens file handles, or socket connections, or whatever on your managed application's behalf, and you never explicitly close them (and don't handle them in a disposer or destructor/finalizer), you can have memory or resource leaks because the runtime cannot manage all of those automatically for you.

唯一的泄漏(除了运行时中可能存在的错误,虽然不太可能是由于垃圾收集)将针对本机资源。如果您 P/Invoke 进入一个本机库,它代表您的托管应用程序打开文件句柄、套接字连接或任何内容,并且您从未明确关闭它们(并且不在处理程序或析构函数/终结器中处理它们),您可以存在内存或资源泄漏,因为运行时无法为您自动管理所有这些。

If you stick with purely managed resources, though, you should be just fine. If you experience any form of memory leak without calling into native code, then that's a bug.

但是,如果您坚持使用纯托管资源,那应该没问题。如果您在没有调用本机代码的情况下遇到任何形式的内存泄漏,那么这是一个错误。

回答by toad

As already mentioned the keeping references around will lead to increasing memory usage over time. An easy way to get into this situation is with events. If you had a long living object with some event that your other objects listen to, if the listeners are never removed then the event on the long lived object will keep those other instances alive long after they are no longer needed.

正如已经提到的,随着时间的推移,保持引用会导致内存使用量增加。进入这种情况的一个简单方法是使用事件。如果您有一个长期存在的对象,其中包含您的其他对象侦听的某些事件,如果这些侦听器从未被删除,那么长期存在的对象上的事件将使那些其他实例在不再需要后很长时间内保持活动状态。

回答by Pontus Gagge

Reflection emitis another potential source of leaks, with e.g. built-in object deserializers and fancy SOAP/XML clients. At least in earlier versions of the framework, generated code in dependent AppDomains was never unloaded...

反射发出是另一个潜在的泄漏源,例如内置对象解串器和花哨的 SOAP/XML 客户端。至少在框架的早期版本中,从不卸载依赖 AppDomains 中生成的代码......

回答by Christian Klauser

Delegates can result in unintuitive memory leaks.

委托可能会导致不直观的内存泄漏。

Whenever you create a delegate from an instance method, a reference to that instance is stored "in" that delegate.

每当您从实例方法创建委托时,对该实例的引用都存储在该委托“中”。

Additionally, if you combine multiple delegates into a multicast delegate, you have one big blob of references to numerous objects that are kept from being garbage collected as long as that multicast delegate is being used somewhere.

此外,如果您将多个委托组合到一个多播委托中,您将拥有一大块对大量对象的引用,只要该多播委托在某处使用,这些对象就不会被垃圾收集。

回答by tranmq

The only reason for memory leak in .NET application is that objects are still being referenced although their life span has ended. Hence, the garbage collector cannot collect them. And they become long lived objects.

.NET 应用程序中内存泄漏的唯一原因是对象仍在被引用,尽管它们的生命周期已经结束。因此,垃圾收集器无法收集它们。它们变成了长寿的物体。

I find that it's very easy to cause leak by subscribing to events without unsubscribing it when the object's life ends.

我发现通过订阅事件而不在对象的生命周期结束时取消订阅它很容易导致泄漏。

回答by Reed Copsey

Event Handlers are a very common source of non-obvious memory leaks. If you subscribe to an event on object1 from object2, then do object2.Dispose() and pretend it doesn't exist (and drop out all references from your code), there is an implicit reference in object1's event that will prevent object2 from being garbage collected.

事件处理程序是非明显内存泄漏的一个非常常见的来源。如果您从 object2 订阅 object1 上的事件,然后执行 object2.Dispose() 并假装它不存在(并从代码中删除所有引用),则 object1 的事件中有一个隐式引用将阻止 object2垃圾收集。

MyType object2 = new MyType();

// ...
object1.SomeEvent += object2.myEventHandler;
// ...

// Should call this
// object1.SomeEvent -= object2.myEventHandler;

object2.Dispose();

This is a common case of a leak - forgetting to easily unsubscribe from events. Of course, if object1 gets collected, object2 will get collected as well, but not until then.

这是泄漏的常见情况 - 忘记轻松取消订阅事件。当然,如果 object1 被收集,object2 也会被收集,但在此之前不会。