title: .Net 4 MemoryCache Leaks with Concurrent Garbage Collection
body: <p>I'm using the new <a href="http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.aspx" rel="nofollow noreferrer">MemoryCache</a> in .Net 4, with a max cache size limit in MB (I've tested it set between 10 and 200MB, on systems with between 1.75 and 8GB of memory).  I don't set any time based expiration on the objects, as I'm using the cache simply as a high performance drive, and as long as there is space, I want it used.  <strong>To my surprise, the cache refused to evict any objects, to the point that I would get <code>SystemOutOfMemory</code> exceptions</strong>.</p>
  
  <p>I fired up <strong>perfmon</strong>, wired up my application to <code>.Net CLR Memory\#Bytes In All Heaps</code>, <code>.Net Memory Cache 4.0</code>, and <code>Process\Private Bytes</code> -- indeed, the memory consumption was out of control, and no cache trims were being registered.</p>
  
  <p>Did some <em>googling</em> and <em>stackoverflowing</em>, downloaded and attached the <a href="http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.aspx" rel="nofollow noreferrer">CLRProfiler</a>, and <em>wham</em>: evictions everywhere!  The memory stayed within reasonable bounds based upon the memory size limit I had set.  Ran it in debug mode again, no evictions.  CLRProfiler again, evictions.</p>
  
  <p>I finally noticed that the profiler forced the application to run without <a href="http://msdn.microsoft.com/en-us/library/yhwwzef8.aspx" rel="nofollow noreferrer">concurrent garbage collection</a> (also see useful <a href="https://stackoverflow.com/questions/2583644/difference-between-background-and-concurrent-garbage-collection">SO Concurrent Garbage Collection Question</a>).  I turned it off in my app.config, and, sure enough, evictions!</p>
  
  <p>This seems like at best an outrageous lack of documentation to not say: <em>this only works with non-concurrent garbage collection</em> -- <strike>though I image since its ported from ASP.NET, they may not have had to worry about concurrent garbage collection</strike>.</p>
  
  <p>So has anyone else seen this?  I'd love to get some other experiences out there, and maybe some more educated insights.</p>
  
  <hr>
  
  <p><strong>Update 1</strong></p>
  
  <p>I've reproduced the issue within a single method: it seems that the cache must be written to in parallel for the cache evictions not to fire (in concurrent garbage collection mode).  If there is some interest, I'll upload the test code to a public repo.  I'm definitely getting toward the deep end of the the CLR/GC/MemoryCache pool, and I think I forgot my floaties...</p>
  
  <hr>
  
  <p><strong>Update 2</strong></p>
  
  <p>I published <a href="http://memorycacheevicttest.codeplex.com/SourceControl/list/changesets" rel="nofollow noreferrer">test code on CodePlex</a> to reproduce the issue.  Also, possibly of interest, the original production code runs in Azure, as a Worker Role.  Interesting, changing the GC concurrency setting in the role's app.config has no effect.  Possibly Azure overrides GC settings much like ASP.NET?  Further, running the test code under WPF vs a Console application will produce slightly different eviction results.</p>