title: ThreadLocal<> and memory leak
body: <p>.Net 4. ThreadLocal&lt;> implements IDisposable. But it seems that calling Dispose() doesn't actually release references to thread local objects being held.</p>
  
  <p>This code reproduces the problem:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Collections.Concurrent;
  using System.Linq;
  using System.Threading;
  
  namespace ConsoleApplication2
  {
      class Program
      {
          class ThreadLocalData
          {
              // Allocate object in LOH
              public int[] data = new int[10 * 1024 * 1024];
          };
  
          static void Main(string[] args)
          {
              // Stores references to all thread local object that have been created
              var threadLocalInstances = new List&lt;ThreadLocalData&gt;();
              ThreadLocal&lt;ThreadLocalData&gt; threadLocal = new ThreadLocal&lt;ThreadLocalData&gt;(() =&gt;
              {
                  var ret = new ThreadLocalData();
                  lock (threadLocalInstances)
                      threadLocalInstances.Add(ret);
                  return ret;
              });
              // Do some multithreaded stuff
              int sum = Enumerable.Range(0, 100).AsParallel().Select(
                  i =&gt; threadLocal.Value.data.Sum() + i).Sum();
              Console.WriteLine("Sum: {0}", sum);
              Console.WriteLine("Thread local instances: {0}", threadLocalInstances.Count);
  
              // Do our best to release ThreadLocal&lt;&gt; object
              threadLocal.Dispose();
              threadLocal = null;
  
              Console.Write("Press R to release memory blocks manually or another key to proceed: ");
              if (char.ToUpper(Console.ReadKey().KeyChar) == 'R')
              {
                  foreach (var i in threadLocalInstances)
                      i.data = null;
              }
              // Make sure we don't keep the references to LOH objects
              threadLocalInstances = null;
              Console.WriteLine();
  
              // Collect the garbage
              GC.Collect();
              GC.WaitForPendingFinalizers();
              GC.Collect();
  
              Console.WriteLine("Garbage collected. Open Task Manager to see memory consumption.");
              Console.Write("Press any key to exit.");
              Console.ReadKey();
          }
      }
  }
  </code></pre>
  
  <p>Thread local data stores a reference to a large object. GC doesn't collect these large objects if references are not nulled manually. I used Task Manager to observe memory consumption. I also run memory profiler. I made a snapshot after garbage was collected. The profiler showed that leaked object is rooted by GCHandle and was allocated with here:</p>
  
  <pre><code>mscorlib!System.Threading.ThreadLocal&lt;T&gt;.GenericHolder&lt;U,V,W&gt;.get_Boxed()
  mscorlib!System.Threading.ThreadLocal&lt;T&gt;.get_Value()
  ConsoleApplication2!ConsoleApplication2.Program.&lt;&gt;c__DisplayClass3.&lt;Main&gt;b__2( int ) Program.cs
  </code></pre>
  
  <p>That seems to be a flaw in ThreadLocal&lt;> design. The trick with storing  all allocated objects for further cleanup is ugly. Any ideas on how to work around that?</p>