在循环图中使用ThreadLocal 时内存泄漏

我刚刚遇到了垃圾收集器关于System.Threading.ThreadLocal这种奇怪的“行为”,我无法解释。 在正常情况下, ThreadLocal实例在超出范围时将被垃圾收集,即使它们没有正确处理,除非它们是循环对象图的一部分。

以下示例演示了此问题:

 public class Program { public class B { public AA; } public class A { public ThreadLocal LocalB; } private static List references = new List(); static void Main(string[] args) { for (var i = 0; i  c.IsAlive)); } static void CreateGraph() { var a = new A { LocalB = new ThreadLocal() }; 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 证实这实际上是一个错误。

原因是你没有调用Dispose。 垃圾收集器只会清理具有终结器的对象作为最后的手段。