在将我的Windows服务安装到生产环境之前,我正在寻找可靠的测试,以确保我的代码不包含内存泄漏。 但是,我在网络上能够找到的只有使用任务管理器查看已使用内存或使用一些付费的内存分析工具。
据我了解,查看任务管理器并不能真正帮助确认内存泄漏(如果有的话)。
如何确认是否存在内存泄漏?
是否有免费的工具可以找到内存泄漏的源头?
注意:我正在使用.Net Framework 4.6和Visual Studio 2015 Community。
在将我的Windows服务安装到生产环境之前,我正在寻找可靠的测试,以确保我的代码不包含内存泄漏。 但是,我在网络上能够找到的只有使用任务管理器查看已使用内存或使用一些付费的内存分析工具。
据我了解,查看任务管理器并不能真正帮助确认内存泄漏(如果有的话)。
如何确认是否存在内存泄漏?
是否有免费的工具可以找到内存泄漏的源头?
注意:我正在使用.Net Framework 4.6和Visual Studio 2015 Community。
你可以使用任务管理器。
但是...
这个免费工具来自微软,非常棒。对于所有存在引用泄漏的程序,这都是必须使用的工具。可以在微软的网站上搜索到。
引用泄漏是指你忘记将对象引用设置为null或它们永远不会离开作用域,并且这几乎和垃圾回收语言一样容易发生,如列表进行累加而不清除、事件处理程序指向委托等。
这是与内存泄漏相当的垃圾回收问题,具有相同的结果。此程序告诉您哪些引用占用了大量内存,您可以知道这是否应该这样,如果不是,则可以找到并解决问题!
它甚至具有一个很酷的可视化界面,显示对象分配了哪些内存(因此您可以追踪错误)。如果需要解释,我相信有youtube视频提供介绍。
注意:您可能需要将应用程序运行为非服务模式才能使用此工具。它会首先启动并运行您的应用程序。您可以使用TopShelf或仅将实现服务集成的guts放在一个dll中,该dll从实现服务集成(服务主机模式)的EXE运行。
虽然托管代码不需要直接管理内存,但您仍然需要管理实例。这些实例“占用”内存。这完全取决于这些实例的使用方式,保持它们在您不希望它们存在时保持活动状态。
只是众多例子之一:错误使用可释放类可能导致大量实例占用内存。对于Windows服务,实例的缓慢但稳定增加最终可能导致过多的内存使用。
是的,有一个分析内存泄漏的工具。 它只是不免费。但是,您可以在7天试用期内识别出问题。
我建议看一下 .NET Memory Profiler。
它非常适合开发期间分析内存泄漏。它使用快照的概念来比较新实例、已释放实例等。这非常有助于了解您的服务如何使用其内存。然后,您可以深入了解为什么会创建新实例或保持活动状态。
是的,您可以测试以确认是否引入内存泄漏。 但是,仅仅拿来就用通常并没有太大的用处。这是因为没有人能预料到运行时会发生什么。该工具可以分析您的应用程序是否存在常见问题,但这并不保证。
然而,您可以使用此工具将内存消耗集成到单元测试框架中,如NUnit
或MSTest
。
https://github.com/fremag/MemoScope.Net
我不认同使用任务管理器来检查是否存在内存泄漏的说法。垃圾收集器的问题在于,它可以根据启发式原则决定在内存暴增后保留内存而不将其返回给操作系统。您可能有2GB的提交大小,但其中90%可以空闲。我不会说垃圾回收器是绝对可靠的。有时候它会在不知不觉中失效,而且问题并不总是那么直接明显。内存流是内存泄漏的常见原因之一。你可以在一个上下文中打开它们,但它们可能永远不会被关闭,即使使用已经包含在using语句中(这是一种应该在使用范围结束后立即清理的可处理对象的定义)。如果你遇到由于内存耗尽而导致的崩溃,Windows会创建转储文件供你查看。
这绝不是一件有趣或容易的事情,而且相当繁琐,但这往往是你最好的选择。
容易造成内存泄漏的常见领域包括使用System.Drawing dll的任何内容、内存流以及如果你正在进行一些严重的多线程操作。
如果您使用Entity Framework和DI模式,可能使用Castle Windsor,那么您很容易出现内存泄漏。
主要的做法是在任何地方都使用using(){}语句,以自动标记对象为已处理。
此外,您还需要关闭Entity Framework上的自动跟踪,仅在读取而不是写入时使用。最好隔离您的写入,在这一点上使用using(){},获取带有跟踪的dbContext,写入您的数据。
如果您想调查堆上的内容。我使用过的最好的工具是RedGate ANTS http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/solving-memory-problems/getting-started,虽然不便宜但它确实有效。
然而,通过在任何地方都使用using(){}模式(不要创建静态或单例DbContext,并且永远不要在大量更新的循环中使用一个上下文,尽可能经常处理它们!),那么您会发现内存通常不是问题。
希望这可以帮助到您。
除非你在处理非托管代码,否则我敢说你不必担心内存泄漏。托管代码中的任何未引用对象都将被垃圾回收器移除,而在.NET框架中找到内存泄漏的可能性,我会说你应该算是非常幸运(或者不幸)。你不必担心内存泄漏。
然而,如果对象的引用从未释放,您仍然可能遇到不断增长的内存使用情况。例如,假设您保留了一个内部日志结构,并且您只是不断向日志列表添加条目。那么每个条目仍然从日志列表中引用,因此永远不会被收集。
根据我的经验,您绝对可以使用任务管理器作为指示器,以确定系统是否存在增长问题;如果内存使用量稳步上升,则知道您有问题。如果它增长到一定程度,但最终收敛到一定大小,则表示它已达到其操作阈值。
如果您想更详细地查看托管内存使用情况,可以下载由Microsoft开发的进程资源管理器。它仍然相当粗略,但比任务管理器提供了更好的统计视图。