Memory Leak When ThreadLocal <T> Used in Loop Graphics
I just stumbled upon this weird “garbage collector” behavior regarding System.Threading.ThreadLocal<T> , which I cannot explain. Under normal circumstances, ThreadLocal<T> instances will garbage collect when they go out of scope, even if they are not positioned correctly, except when they are part of the cyclic object graph.
The following example demonstrates the problem:
public class Program { public class B { public AA; } 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(); } } Although not calling Dispose not good practice, it is a CLR project to clean up resources (by calling a finalizer) in the end, even if Dispose not called.
Why does ThreadLocal behave differently in this regard and can lead to memory leaks if they are not allocated correctly in the case of a cyclic schedule? Is it for design? And if so, where is this documented? Or is this a bug in the GC CLR?
(Tested under .NET 4.5).