2011-05-17 60 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