我有一个用VB.NET(.NET 4.5.2)编写的控制台程序,它充当服务。连续循环运行,然后等待MSMQ队列上的消息,并处理该消息。不知何故,这个程序有很大的内存泄漏。我已经完成了所有代码,并尽我所能使用Using语句,但问题仍然存在。循环次数越多,程序使用的内存越多,垃圾收集器就不会回收这个内存。
我最终在循环的底部放置了一个GC.Collect(),并且能够释放大部分内存。但是,我意识到这是不好的做法,可能会导致问题。只是想知道是否有办法检查GC.Collect()摆脱了哪些变量,所以我可以找到问题的根源?
Do While (True)
' Code to wait for message on a queue
' Code to process message (includes calls to class library)
GC.Collect()
Loop
答案 0 :(得分:2)
如果垃圾收集器在手动调用时释放内存,则不会泄漏内存。托管内存环境中的泄漏是GC无法释放的内存,因为它在对象图上的某处被引用。
可能是他们的代码使用了被提升为gen1,gen2或大对象堆的对象实例。这些世代的实例收集频率低于gen0。 Windows资源监视器包含许多performance counters that can be used to profile the behavior of the managed heap。我猜你可能有对象被提升为gen2。跟踪“Gen 1 Promoted Bytes / Sec”计数器可以让您了解这是否正在发生。
在托管内存环境中,GC在存在内存压力时运行,而不是在不再需要对象实例时运行,因此仅增加内存使用量并不一定是泄漏的迹象。
如果你取出Collect
,内存使用总是会增加(比如几分钟或队列中正在处理的消息),还是上下有点像一个浪潮?如果是后者只是让GC做它的事情,你就没有泄漏。
Visual Studio具有许多内存分析功能https://msdn.microsoft.com/en-us/library/dn342825.aspx
SOS托管调试器扩展是一个非常强大的工具,用于筛选托管堆,尽管它不适合胆小的人。 https://docs.microsoft.com/en-us/dotnet/framework/tools/sos-dll-sos-debugging-extension