C# 哪些策略和工具可用于查找 .NET 中的内存泄漏?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/134086/
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
What strategies and tools are useful for finding memory leaks in .NET?
提问by Scott Langham
I wrote C++ for 10 years. I encountered memory problems, but they could be fixed with a reasonable amount of effort.
我写了 10 年 C++。我遇到了内存问题,但可以通过合理的努力来修复它们。
For the last couple of years I've been writing C#. I find I still get lots of memory problems. They're difficult to diagnose and fix due to the non-determinancy, and because the C# philosophy is that you shouldn't have to worry about such things when you very definitely do.
在过去的几年里,我一直在编写 C#。我发现我仍然有很多内存问题。由于不确定性,它们很难诊断和修复,并且因为 C# 哲学是,当您非常肯定地这样做时,您不应该担心这些事情。
One particular problem I find is that I have to explicitly dispose and cleanup everything in code. If I don't, then the memory profilers don't really help because there is so much chaff floating about you can't find a leak within all the data they're trying to show you. I wonder if I've got the wrong idea, or if the tool I've got isn't the best.
我发现的一个特殊问题是我必须明确地处理和清理代码中的所有内容。如果我不这样做,那么内存分析器并没有真正的帮助,因为有太多的箔条漂浮在你身上,你无法在他们试图向你展示的所有数据中找到泄漏。我想知道我是否有错误的想法,或者我拥有的工具不是最好的。
What kind of strategies and tools are useful for tackling memory leaks in .NET?
什么样的策略和工具可用于解决 .NET 中的内存泄漏?
采纳答案by GEOCHET
I use Scitech's MemProfilerwhen I suspect a memory leak.
当我怀疑内存泄漏时,我使用Scitech的MemProfiler。
So far, I have found it to be very reliable and powerful. It has saved my bacon on at least one occasion.
到目前为止,我发现它非常可靠和强大。它至少有一次救了我的培根。
The GC works very well in .NET IMO, but just like any other language or platform, if you write bad code, bad things happen.
GC 在 .NET IMO 中工作得很好,但就像任何其他语言或平台一样,如果你编写了错误的代码,就会发生糟糕的事情。
回答by Zac Gochenour
You still need to worry about memory when you are writing managed code unless your application is trivial. I will suggest two things: first, read CLR via C#because it will help you understand memory management in .NET. Second, learn to use a tool like CLRProfiler(Microsoft). This can give you an idea of what is causing your memory leak (e.g. you can take a look at your large object heap fragmentation)
在编写托管代码时,您仍然需要担心内存问题,除非您的应用程序是微不足道的。我将建议两件事:首先,通过 C#阅读CLR,因为它将帮助您理解 .NET 中的内存管理。其次,学习使用像CLRProfiler(Microsoft)这样的工具。这可以让您了解导致内存泄漏的原因(例如,您可以查看大对象堆碎片)
回答by Mark
We've used Ants Profiler Proby Red Gate software in our project. It works really well for all .NET language-based applications.
我们在我们的项目中使用了 Red Gate 软件的Ants Profiler Pro。它适用于所有基于 .NET 语言的应用程序。
We found that the .NET Garbage Collector is very "safe" in its cleaning up of in-memory objects (as it should be). It would keep objects around just because we mightbe using it sometime in the future. This meant we needed to be more careful about the number of objects that we inflated in memory. In the end, we converted all of our data objects over to an "inflate on-demand" (just before a field is requested) in order to reduce memory overhead and increase performance.
我们发现 .NET 垃圾收集器在清理内存对象时非常“安全”(应该是这样)。它会保留对象,只是因为我们将来可能会使用它。这意味着我们需要更加小心我们在内存中膨胀的对象数量。最后,我们将所有数据对象转换为“按需膨胀”(就在请求字段之前),以减少内存开销并提高性能。
EDIT: Here's a further explanation of what I mean by "inflate on demand." In our object model of our database we use Properties of a parent object to expose the child object(s). For example if we had some record that referenced some other "detail" or "lookup" record on a one-to-one basis we would structure it like this:
编辑:这是我所说的“按需膨胀”的进一步解释。在我们数据库的对象模型中,我们使用父对象的属性来公开子对象。例如,如果我们有一些记录在一对一的基础上引用了其他“详细信息”或“查找”记录,我们会将其结构如下:
class ParentObject
Private mRelatedObject as New CRelatedObject
public Readonly property RelatedObject() as CRelatedObject
get
mRelatedObject.getWithID(RelatedObjectID)
return mRelatedObject
end get
end property
End class
We found that the above system created some real memory and performance problems when there were a lot of records in memory. So we switched over to a system where objects were inflated only when they were requested, and database calls were done only when necessary:
我们发现,当内存中有大量记录时,上述系统会产生一些实际内存和性能问题。因此,我们切换到一个系统,其中对象仅在被请求时才膨胀,并且仅在必要时才进行数据库调用:
class ParentObject
Private mRelatedObject as CRelatedObject
Public ReadOnly Property RelatedObject() as CRelatedObject
Get
If mRelatedObject is Nothing
mRelatedObject = New CRelatedObject
End If
If mRelatedObject.isEmptyObject
mRelatedObject.getWithID(RelatedObjectID)
End If
return mRelatedObject
end get
end Property
end class
This turned out to be much more efficient because objects were kept out of memory until they were needed (the Get method was accessed). It provided a very large performance boost in limiting database hits and a huge gain on memory space.
事实证明,这样做效率更高,因为在需要对象(访问 Get 方法)之前,它们一直处于内存不足状态。它在限制数据库命中和内存空间的巨大收益方面提供了非常大的性能提升。
回答by Gord
The best thing to keep in mind is to keep track of the references to your objects. It is very easy to end up with hanging references to objects that you don't care about anymore. If you are not going to use something anymore, get rid of it.
要记住的最好的事情是跟踪对您的对象的引用。最终很容易挂起对您不再关心的对象的引用。如果您不再打算使用某些东西,请摆脱它。
Get used to using a cache provider with sliding expirations, so that if something isn't referenced for a desired time window it is dereferenced and cleaned up. But if it is being accessed a lot it will say in memory.
习惯于使用具有滑动到期时间的缓存提供程序,以便如果在所需的时间窗口内未引用某些内容,则会取消引用并清理它。但是如果它被大量访问,它会在内存中说。
回答by Stuart McConnell
One of the best tools is using the Debugging Tools for Windows, and taking a memory dump of the process using adplus, then use windbgand the sosplugin to analyze the process memory, threads, and call stacks.
最好的工具之一是使用Windows 调试工具,并使用adplus对进程进行内存转储,然后使用windbg和sos插件来分析进程内存、线程和调用堆栈。
You can use this method for identifying problems on servers too, after installing the tools, share the directory, then connect to the share from the server using (net use) and either take a crash or hang dump of the process.
您也可以使用此方法来识别服务器上的问题,安装工具后,共享目录,然后使用 (net use) 从服务器连接到共享,并进行进程的崩溃或挂起转储。
Then analyze offline.
然后离线分析。
回答by Chris Ballard
If the leaks you are observing are due to a runaway cache implementation, this is a scenario where you mightwant to consider the use of WeakReference. This could help to ensure that memory is released when necessary.
如果您观察到的泄漏是由于失控的缓存实现造成的,那么在这种情况下您可能需要考虑使用 WeakReference。这有助于确保在必要时释放内存。
However, IMHO it would be better to consider a bespoke solution - only you really know how long you need to keep the objects around, so designing appropriate housekeeping code for your situation is usually the best approach.
然而,恕我直言,最好考虑一个定制的解决方案 - 只有你真正知道你需要将对象保留多长时间,所以为你的情况设计合适的内务管理代码通常是最好的方法。
回答by Jay Bazuzi
Just for the forgetting-to-dispose problem, try the solution described in this blog post. Here's the essence:
对于忘记处理问题,请尝试此博客文章中描述的解决方案。这是本质:
public void Dispose ()
{
// Dispose logic here ...
// It's a bad error if someone forgets to call Dispose,
// so in Debug builds, we put a finalizer in to detect
// the error. If Dispose is called, we suppress the
// finalizer.
#if DEBUG
GC.SuppressFinalize(this);
#endif
}
#if DEBUG
~TimedLock()
{
// If this finalizer runs, someone somewhere failed to
// call Dispose, which means we've failed to leave
// a monitor!
System.Diagnostics.Debug.Fail("Undisposed lock");
}
#endif
回答by Timothy Lee Russell
Are you using unmanaged code? If you are not using unmanaged code, according to Microsoft, memory leaks in the traditional sense are not possible.
您使用的是非托管代码吗?如果您不使用非托管代码,根据 Microsoft 的说法,传统意义上的内存泄漏是不可能的。
Memory used by an application may not be released however, so an application's memory allocation may grow throughout the life of the application.
然而,应用程序使用的内存可能不会被释放,因此应用程序的内存分配可能会在应用程序的整个生命周期中增长。
From How to identify memory leaks in the common language runtime at Microsoft.com
A memory leak can occur in a .NET Framework application when you use unmanaged code as part of the application. This unmanaged code can leak memory, and the .NET Framework runtime cannot address that problem.
Additionally, a project may only appear to have a memory leak. This condition can occur if many large objects (such as DataTable objects) are declared and then added to a collection (such as a DataSet). The resources that these objects own may never be released, and the resources are left alive for the whole run of the program. This appears to be a leak, but actually it is just a symptom of the way that memory is being allocated in the program.
从Microsoft.com 上的如何识别公共语言运行时中的内存泄漏
当您将非托管代码用作应用程序的一部分时,.NET Framework 应用程序中可能会发生内存泄漏。此非托管代码可能会泄漏内存,而 .NET Framework 运行时无法解决该问题。
此外,项目可能只出现内存泄漏。如果声明了许多大对象(例如 DataTable 对象),然后将其添加到集合(例如 DataSet)中,则会发生这种情况。这些对象拥有的资源可能永远不会被释放,并且这些资源在程序的整个运行过程中都处于活动状态。这看起来是一个泄漏,但实际上它只是程序中内存分配方式的一种症状。
For dealing with this type of issue, you can implement IDisposable. If you want to see some of the strategies for dealing with memory management, I would suggest searching for IDisposable, XNA, memory managementas game developers need to have more predictable garbage collection and so must force the GC to do its thing.
为了处理此类问题,您可以实现IDisposable。如果您想了解一些处理内存管理的策略,我建议您搜索IDisposable、XNA、内存管理,因为游戏开发人员需要更多可预测的垃圾回收,因此必须强制 GC 执行其操作。
One common mistake is to not remove event handlers that subscribe to an object. An event handler subscription will prevent an object from being recycled. Also, take a look at the usingstatement which allows you to create a limited scope for a resource's lifetime.
一个常见的错误是不删除订阅对象的事件处理程序。事件处理程序订阅将阻止对象被回收。另外,看看using语句,它允许您为资源的生命周期创建有限的范围。
回答by Constantin
Big guns - Debugging Tools for Windows
Big guns - Windows 调试工具
This is an amazing collection of tools. You can analyze both managed and unmanaged heaps with it and you can do it offline. This was very handy for debugging one of our ASP.NET applications that kept recycling due to memory overuse. I only had to create a full memory dump of living process running on production server, all analysis was done offline in WinDbg. (It turned out some developer was overusing in-memory Session storage.)
这是一个惊人的工具集合。您可以使用它分析托管和非托管堆,并且可以离线进行。这对于调试由于内存过度使用而不断回收的 ASP.NET 应用程序之一非常方便。我只需要创建在生产服务器上运行的活动进程的完整内存转储,所有分析都是在 WinDbg 中离线完成的。(事实证明,一些开发人员过度使用内存会话存储。)
"If broken it is..."blog has very useful articles on the subject.
“如果坏了就是……”博客上有关于这个主题的非常有用的文章。