Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MemoryCache Empty : Returns null after being set

I have a problem with an MVC 3 application that is using the new .NET 4 System.Runtime.Caching MemoryCache. I notice that after a seemingly unpredictable time, it stops caching stuff, and acts like it's empty. Consider this bit of code that I took straight from a test View in ASP.NET MVC:

MemoryCache.Default.Set("myname","fred", new CacheItemPolicy() { SlidingExpiration = new TimeSpan(0,5,0) }); Response.Write(MemoryCache.Default["myname"]); 

When it's working, predictably "fred" gets printed. However, when the problem starts to occur, despite the Set(), the value of MemoryCache.Default["myname"] is null. I can prove this by setting a breakpoint on the Response.Write() line and directly setting and reading from the cache using the Immediate Window - It just won't set it and stays null! The only way to get it working again then is to cause an AppDomain recycle.

Intriguingly I can provoke the problem into occurring when the app is working normally by breaking on the Response.Write() line and running MemoryCache.Default.Dispose(). After that, MemoryCache.Default is not null itself (why is this?), but won't save anything set on it. It doesn't cause any errors, but just won't save anything.

Can anybody verify this and explain? As I believe I have discovered, when the app stops working on its own, something is Disposing MemoryCache.Default, but it's not me!


UPDATE

Well, I'm sick of this prob now! CLRProfiler doesn't seem to work with MVC 3. SciTech's CLR tool was good - so was RedGate ANTS. But all they told me was that the MemoryCache object is being disposed by something! I also proved (via a timestamp print) that a PartialView on my page that should be cached (specified by OutputCacheAttribute) stops being cached after a few minutes - it starts refreshing with every call to the page. Just to clarify the environment, I am running directly on the IIS 7.5 server on my development workstation running Win 7 Ultimate. The memory tools mentioned above suggest I am only using about 9mb of memory in terms of objects in play.

In desperation I have changed my caching code to first search for an ambient HttpContext to hook onto and use its Caching functionality, if one's available. Early tests show this is reliable, but it feels like a nasty hack.

Am getting the feeling that MemoryCache and OutputCache aren't warranted to work with MVC 3...

like image 459
James McCormack Avatar asked Sep 14 '11 20:09

James McCormack


People also ask

Is MemoryCache set thread safe?

MemoryCache is threadsafe. Multiple concurrent threads can read and write a MemoryCache instance. Internally thread-safety is automatically handled to ensure the cache is updated in a consistent manner.

How do I clear my MemoryCache default?

You can dispose the MemoryCache. Default cache and then re-set the private field singleton to null, to make it recreate the MemoryCache. Default.

Should I dispose MemoryCache?

MemoryCache implements IDisposable so you should call Dispose before replacing the old instance.

Is MemoryCache a singleton?

Note that the MemoryCache is a singleton, but within the process. It is not (yet) a DistributedCache. Also note that Caching is Complex(tm) and that thousands of pages have been written about caching by smart people.


2 Answers

So, here's some news. We looked into this and YES, this is a bug in .NET 4.

The good news is that it was fixed in .NET 4.5, so if you can, update your installation to .NET 4.5 and you're solid.

The other good news it that this fix has been back-ported to .NET 4 and will be available as a QFE (Quick Fix...a one off fix you'll apply) #578315. It was backported/fixed just days ago and it should be out ASAP. I'll try to get an exact date, but it's soon.

The other other good news is that there's a workaround for this on .NET 4 before the QFE. The workaround is weird, but it could unblock you.

using (ExecutionContext.SuppressFlow())     {           // Create memory cache instance under disabled execution context flow          return new YourCacheThing.GeneralMemoryCache(…); } 

Hope this helps.

UPDATE: The Hotfix is http://support.microsoft.com/kb/2828843 and you can request it here: https://support.microsoft.com/contactus/emailcontact.aspx?scid=sw;%5BLN%5D;1422

like image 81
Scott Hanselman Avatar answered Sep 21 '22 05:09

Scott Hanselman


We have the same problem. I confirm that after some period of time cache became disposed. It's private field _disposed became 1. I am sure that I don't have call to cache.Dispose in my code. But when I looked at code of MemoryCache with Reflector I saw, that in constructor it subscribes on two events

domain.DomainUnload += eventHandler; domain.UnhandledException += exceptionEventHandler;  private void OnAppDomainUnload(object unusedObject, EventArgs unusedEventArgs) {   this.Dispose(); }  private void OnUnhandledException(object sender, UnhandledExceptionEventArgs eventArgs) {   if (!eventArgs.IsTerminating)     return;   this.Dispose(); } 

Both of these event handlers have call to Dispose. May be after some domain recycling in IIS it causes domain unload, but keeps cache in memory(i'am not shure if it is possible).

like image 22
Dima Avatar answered Sep 19 '22 05:09

Dima