在循环图中使用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。 垃圾收集器只会清理具有终结器的对象作为最后的手段。