我剛剛遇到了垃圾回收器的這個奇怪的'行爲',涉及System.Threading.ThreadLocal<T>
,我無法解釋。在一般情況下,即使它們沒有正確處理,當它們超出範圍時,它們也會被垃圾收集,除非它們是循環對象圖的一部分。ThreadLocal的內存泄露<T>用於循環圖
下面的例子說明這個問題:
public class Program
{
public class B { public A A; }
public class A { public ThreadLocal<B> LocalB; }
private static List<WeakReference> references = new List<WeakReference>();
static void Main(string[] args) {
for (var i = 0; i < 1000; i++)
CreateGraph();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
// Expecting to print 0, but it prints 1000
Console.WriteLine(references.Count(c => c.IsAlive));
}
static void CreateGraph() {
var a = new A { LocalB = new ThreadLocal<B>() };
a.LocalB.Value = new B { A = a };
references.Add(new WeakReference(a));
// If either one of the following lines is uncommented, the cyclic
// graph is broken, and the programs output will become 0.
// a.LocalB = null;
// a.LocalB.Value = null;
// a.LocalB.Value.A = null;
// a.LocalB.Dispose();
}
}
雖然沒有要求Dispose
是不是好的做法,但它是CLR的設計,最終清理資源(通過調用終結器),即使Dispose
不叫。
爲什麼ThreadLocal
在這方面的行爲有所不同,並且在循環圖的情況下如果處理不當,會導致內存泄漏?這是設計嗎?如果是這樣,那麼記錄在哪裏?或者這是CLR GC中的錯誤?
(在.NET 4.5下測試)。
[David Kean](https://twitter.com/davkean)證實這是一個錯誤。 – Steven
[點擊](https://mobile.twitter.com/davkean/status/655067698511024128)。 – Steven