I’ve just spent the last week or so doing some testing on our ASP.NET application. We’re in the process of porting it from ASP.NET 1.1 to 2.0 and it’s been an intriguing voyage of discovery so far. But after a random period of time the software would stop working – page postbacks would fail, data we were storing in the cache was disappearing and it was driving me crazy! The only way to get things working was to reboot my machine. One step forward, two steps back.
I eventually figured out what the problem was (I had several red herrings to work through first as is always the case in such things). I put a callback onto inserts into the cache to determine why items were being cleared out of it and interestingly at certain points I’d add something and it would be removed immediately with a reason of “underused”. This is ASP.NET’s memory collection at work deciding that as my machine is so low on resources it would try and save as much as possible. The following change to web.config (in the System.Web section) sorted it out:
<caching> <cache disableMemoryCollection = "true" disableExpiration = "false" privateBytesLimit = "0" percentagePhysicalMemoryUsedLimit = "90" privateBytesPollTime = "00:02:00"/> </caching>
The reason I was getting the problem so often was that my work laptop died and the one I’m using until I get it fixed is far less powerful and has a lot less memory. So it was happening frequently on my machine, less frequently on everyone else’s, even less frequently on our test server and very rarely on our live server (the problem also effected our ASP.NET 1.1 version). Still, it’s a nice feeling to have figured it out.
Of course the real problem wasn’t the cache recycling at all – it’s perfectly natural that the cache should clear itself out when it wants. The problem was that when a particular object was no longer found in the cache by our software, the code wasn’t properly re-populating it from the database. So with that fixed we shouldn’t need to turn off the memory collection at all.
And to think, if it wasn’t for my laptop expiring this would probably have remained a random, undiagnosed crash for quite some time yet. It’s a tricky old game this debugging one…
An “intriguing voyage of discovery”, eh? That explains the blue language coming from your corner of the office…
That deserves another post but I’ll wait until I’ve calmed down a bit!
The real problem is that you’re not using Ruby on Rails! 😉
The joy of a black box OS. I so miss those days of guessing what is wrong for weeks on end, only to discover that it’s the flange-reamer on the flywheel to the left of that thing we found last year that wasn’t documented.
You need to move to the dark side John.
John: I’ll get round to reading that book soon, I swear it!
Andy: Sometimes I think that it’s me on the dark side and you on the righteous path to enlightenment!
You’re a star.
This has been puzzling me for ages as my development website was running slooooow.
Well done figuring this out – and thanks!
Please advise where your roadside shrine is located so that I may deposit fruit and nuts. You’ve saved me chucking my (weak) staging box out the window.
dude, i luv you, been fighting with this behavior like 3 months
John you are THE debugging champion…thanks a ton !
After experiencing problems where my cache keeps being invalidated I stumbled on your post here. It solved it.
Thank guru you saved my lot of time, i was working with subsonic and trying to cache it but in debug break point the cache object immediately on next line return the null object. i thought this is the problem of subsonic and i wasted lot of time searching for subsonic fixes.then some how i thought that may b this the problem with the cache and i came to your article via google and my problem is solved thank you very much for this information.
I’ve given up on the ASP.NET cache object and have gone to a custom solution that uses an application variable instead of the cache object….
Something like this:
private class AppCache
public Expires as datetime
public Data as object
then, in the code, it works looks something like this…
dim appvar as AppCache
dim mydataelement as someclass
appvar = application(“AppCache”)
if appvar is nothing orelse appvar.expires <= datetime.now then
‘Either the application variable isn’t set, or it has expired
‘Run your refresh here….
mydataelement = ctype(appvar.Data,someclass)
I’ve found through extensive load and stress testing that this method uses just a little more CPU to maintain, but a lot less memory, and you don’t have to worry so much about IIS killing off older objects.
Also, you might be able to mitigate some of your issues by setting a recycle frequency on your app pools. This really isn’t optimal, but it can help remediate cache issues without overriding the garbage collection routines IIS does to clean up after itself.
The thing you have to watch with that approach (which is to store your cache in the global application object) is that it’s no longer thread safe – which the global cache is – so you’d have to ensure that you lock reads and writes if you want it to hold up to real world usage. Of course it all depends on your individual requirements what you go with!
I’m glad that I found this. I had the same problem and ready to give up until I found this post. I solved my problem. I’m using.Net framework 4.