Original address: Http://blogs.msdn.com/b/tess/archive/2006/08/11/695268.aspx
"we use the Page.cache to store temporary data and we have the recently discovered that it causes high memory consumption. The bad thing are that the memory never goes down even though the cache items has expired, and we suspect a possible memor Y leak in its implementation.
We have the created this simple page:
protected void Page_Load (object sender, EventArgs e) {
This. PAGE.CACHE.ADD (Guid.NewGuid (). ToString (), Guid.NewGuid (). ToString (), NULL, DateTime.MaxValue, Timespan.fromminutes (1),
Cacheitempriority.notremovable, New CacheItemRemovedCallback (this. onremoved));
}
public void onremoved (string key, object value, CacheItemRemovedReason r)
{
value = NULL;
}
which we stress with ACT (application Center Test) for 5 minutes. Memory usage peaks at (MB), and after some time it decreases to 253 MB, but never goes down completely even though we WA Ited for ten minutes after the stress test. Our expectation is, the memory should go down to about 50-60 MB.
The question is does the above scenario fall into the category of memory leaks? "
I had thoroughly enjoyed the quizzes that Rico Mariani and Mike Stall had on their blogs, so I do a copy cat ... and i hav E to say I really liked the results, both because I thought the answers were really good and contained details that I Woul D probably has missed, and also because it brought up some new questions that I didn ' t think off.
If you haven ' t looked at the quiz yet, I would recommend your do, and especially the comments ...
answers/summary:
Before I start, I want to say the I am not so naive that I claim the We products is completely bug free, no software E Ver is ... but when I get a proof and don ' t agree with the results (especially when it's such a commonly used feature as C Ache) I get as suspicious as Dr House:) and start scrutinizing the test. This is partially why I brought this question up as a post to begin with ... i.e. because I think it is important so in any situation where does a stress test or a proof of concept it is very imp Ortant that's know the underlying platform in order to interpret the results correctly.
As I mentioned there were a lot of good comments in the quiz, as well as many good questions so I'll divide the points I Nto different sections.
1. The CacheItemRemovedCallback
2. The stress test and garbage collection
3. Sliding Expiration and Absolute expiration
4. cacheitempriority.notremovable
5. Page.cache vs. Cache vs. application
6. Real-life Scenario vs. Stress test for Proof
7. A Small comment on timers
The CacheItemRemovedCallback
The first thing I noticed when looking at the results given is, that is, MB seemed like a insane amount for this tests. Even if nothing is removed from cache, the items stored in cache (GUID ' s) is relatively small and would never amount to That's much, so something smells very fishy. As Matt correctly pointed out in this comment, we is running into an issue where we is connecting an instance Eventhandl Er with a cache object, which effectively causes us-to-cache the whole page and all its contents.
To get more info on this see my earlier post about "The eventhandlers that made the memory balloon". In this particular case it was not necessary to set the value to null. The GUID would be un-rooted when it was removed. If you had a situation where do need to dispose of the object that was stored in cache and you would has to use a static EV Enthandler of some kind.
Performing this minor change we can get the same stress test to peak at a instead of about, which is a major improvement . But even still the objects is not removed from memory when the cache expires ... so on to the next point ...
The stress test and garbage collection
When doing a stress test like the it is very important to understand a few things. The first is what to interpret the results and the second was to understand the platform we be working with and the Behavio R of the garbage collector.
The the the data that we looked at is memory usage for the process in TaskManager, alternatively private bytes in PE Rformance Monitor. The question really doesn ' t tell, but in my private tests I is looking at private bytes in Performance Monitor.
What I would being really interested in are
A) is the objects removed properly from cache?
b) Does the size of the managed heaps decrease (i.e is the. NET objects stored in cache actually collected)? and
c) What happens with the size of the process and what would happen if we run the test a second time, i.e. would it increase By the same amount or would memory be reused etc.
So I added the counter ASP. NET Apps V2.0.50727/cache Total Entries, and saw that it increased gradually with the test, and Then every so often I got a dip that created a sawtooth pattern in the cache total Entries, indicating that cache Entries Were being released and new ones came in. Then I stopped the test and waited, and after 1 minute (approx.) There is a huge dip, and then after another minute there Was another huge dip, and after about 5 minutes my Cache total Entries count is down to 0.
Conclusion #1. My objects is no longer rooted by the cache and should is available for garbage collection and removal, but ... they is n Ever collected, why oh why?
Petros pointed out if this is because after the stress test, we had no activity, so nothing caused a GC, and thus nothin G'll get collected even if it's available for collection. The most common mistake if performing a stress test (see my post about why un-rooted objects was not garbage col lected here for more info)
So, how can we do? Well, if I am trying to stress a leak, and want to verify if it really are a leak, I usually introduce a page with the Foll Owing code
Gc. Collect ();
Gc. WaitForPendingFinalizers ();
Gc. Collect ();
And run this after the stress test. caution! I wouldn ' t recommend calling this on production, just to clean up memory unless you had a really good reason and can make Sure that it isn't called so often that it throws the GC's own mechanism for determining generation limits etc. and so T Hat it doesn ' t cause high CPU issues. Think twice and three and four times before putting this in production. It is great for after a stress test though ... to simulate the next time a full GC comes in without have to create alloca tions to cause it.
With this on place I could see that my. NET CLR memory/bytes in all heaps, went down all the the-to-1.5 MB after the Colle Ction, which means that all the objects I cached etc. were gone, and everything is successful, so we don't have a leak in The Cache mechanism. Yay!!!
Conclusion #2: The objects would has been gone if a full collection would has occurred.
But, wait a minute ... my private bytes didn ' t go down as much as I would there thought ...
Jcornwell brought up a interesting point ... Even if we do collect and the bytes in all heaps is all nicely down to a minimum, we don ' t necessarily Decommitt all memo Ry and return it to the OS. If we had to does this all the time performance would decrease significantly ... but ... it is not really a problem for us, it is just a food for thought when looking at the results. See, If I run the same test again, we'll reuse this memory, so it's by no means leaked ...
Conclusion #3: It's important to know how the garbage collector works and what the important counters and values were to C Orrectly interpret a result.
Sliding Expiration and Absolute expiration
No one touched on this, but I wanted to bring it up because it is something that caught my eye when I saw the sample. In this case we had a sliding expiration of 1 minute and an absolute expiration of datetime.maxvalue ...
Ok, I have to admit, I don't know all the method signatures and things by hand but just seeing the sample I am a bit conf Used about if the cache items should expire after 1 minute or after whatever insanely long amount of time Datetime.maxvalu E might be. And I got even more confused when I looked it on MSDN in order to see which took precedence, and found that I was Suppo Sed to has gotten an argument exception if I used both a sliding and absolute expiration, but I clearly didn ' t get an exc Eption ...
I even got so perturbed the had to hooks up WinDbg (surprise, surprise) and make super sure that I didn ' t get an Excepti On and even then I didn ' t trust it ...
So I went to the code and found that MaxValue = cache.noabsoluteexpiration ... I later found out which this is documented in MSDN:) but I had more fun finding it out using reflector.
Soooo. We were using the sliding expiration but I wanted to bring it up, since it confused me, and perhaps would confuse Other people too ...
Cacheitempriority.notremovable
This one caused a bit of discussion when Scott said he thought that it's better to isn't use notremovable and build in Logi C to re-populate the cache when needed. I think it was a good point, and that's notremovable has it's benefits too in some cases.
Just to clarify. Notremovable means that the item would be available for collection when the cache item had expired but not before. If the cache item is removable, the cache item is eligible for removal before it expiration if memory usage is.
One specific location where it had a benefit is in ASP. Session implementation. As you were probably all aware by now (from my ramblings in previous posts), InProc session was stored in cache. The session objects was stored with a cacheitempriority of notremovable since there was no to repopulate these if they is deleted. I believe you should choose cacheitempriority based on the cost and possibility of re-populating the cache. But does feel free to disagree with me:)
Page.cache vs. Cache vs. application
What I really wanted to get out of the the the question about the difference between Page.cache and Cache were that there really are No difference. They is pointing to the same object. The cache is application specific (AppDomain specific), and in the event of an AppDomain recycle it's emptied out.
The application is very similar to the Cache, where that it's a static object with a dictionary like structure. This was saved as a legacy from ASP, and I had yet to find a reason to use it instead of just using Cache.
Real-life scenario vs. Stress test for repro.
A Few people mentioned that the test didn ' t seem realistic. I agree, but I also don ' t think the intent of the sample above is to is realistic, rather I think the person who wrote th e email wrote the sample this by-quickly and easily determine if there was a memory leak, since it's a lot faster and Cleaner than trying to repro and the full application.
A Small comment on timers
Finally, I just want to comment in a timers issue that I had mentioned before.
If you run on 1.1. And you see that your cache items aren ' t expiring (the cache total Entries) your may is running into this problem Http://suppor T.microsoft.com/kb/900822/en-us where timers is not firing properly. But that's isn't the case in my stress test.
Laters y ' all.
Did the This blog post help you resolve a problem?
(reprinted) ASP. Quiz answers:does page.cache leak memory?