2011-05-17 51 views
7

我有一个.NET System.Threading.Timer计时器,每60秒钟滴答一次,并在每个滴答引入一个内存泄漏。当我的计时器滴答.... .NET内存泄漏

在计时器的每个滴答声上,代码分配一个IDisposable对象(称为SocketsMessageConnector)...但我确实正确地处理它。我运行了.NET Memory Profiler,每隔60秒我就看到一个SocketsMessageConnector类的新实例在内存中徘徊(所以15分钟后,我有15个实例)。内存分析器验证该实例实际上是否处置完毕,但是它显示的是由一个TimerCallback植入的实例,该实例根植于一个以GCHandle为根的_TimerCallback ...

这是怎么回事?为什么TimerCallback会保留在每个计时器上创建的新实例?

PS。剖析器在拍摄快照之前强制使用2个GC,因此我知道这实际上是泄漏,而不仅仅是GC的优化。

+0

你可以发布一些代码给我们看看吗? – Nate 2011-05-17 16:59:18

+5

我读了这个问题,并认为“当我的计时器轻轻泄漏” – 2011-05-17 17:15:18

回答

7

仅仅因为它已经被处置了,并不意味着它已经被垃圾收集了。

尝试改变你的计时器,每秒运行两次,然后让它运行10分钟。现在检查你的类对象有多少仍然“在内存中徘徊”。如果你真的有内存泄漏,你将有1200个对象。但是,如果垃圾收集已经跳入,你会有很少 - 也许低于100.

+0

探测器强制两个垃圾收集,我认为这将足以清理未引用的实例...但无论如何,我已经看到它起来到150个实例。我会让计时器更小,并尝试... – Jeff 2011-05-17 17:06:56

+0

嗯,这很奇怪...我改变了间隔运行每100ms ...一旦内存超过200MB起来,它开始正确GC和旧实例开始走开... – Jeff 2011-05-17 17:16:43

+0

记住,收集不一定实际上发生,直到GC决定这是一个好时机。此外,一旦CLR不再需要它,交由你的应用程序交给你的应用程序的内存不一定会立即回传。内存分配相当复杂。看看Process Explorer并观察Mark Russinovich解释所有不同的内存列,你会明白我的意思。 – Tom 2011-05-29 01:11:58