Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Large Gen 0 Heap in .NET, wasting memory?

I have an ASP.NET / C# web application that is using a lot of memory.

ANTS Memory Profiler and PerfMon both show my Gen 0 heap growing rapidly to about 1 GB in size during Application_Start. I read here that the PerfMon counter for Gen 0 Heap is actually showing the "budget" for Gen 0, not the size (which I take to mean not all that memory is part of the private working set of the process?). However the ANTS profiler does show about 700 MB of "unused memory allocated to .NET", and this does seem to be part of the private working set of the process (as reported in taskmgr). I am guessing this large amount of unused memory is related to the large Gen 0 heap.

What is happening in Application_Start while this happens is that I'm in a while loop reading about a million rows from a SqlDataReader. These are being used to populate a large cache for later use. Given this, the obvious culprit for the large amount of unused memory was large object heap fragmentation, but I don't think this is the case as I'm pre-allocating more than is needed for my large cache object. To be certain, I even tried commenting out the part of the loop that actually adds to my cache object; it made no difference in the amount of unused memory allocated.

As a test, I tried frequently forcing garbage collection of gen 0 during the loop (against all recommendations, I know), and this caused the size of the gen0 heap to stay down around 128 MB and also resulted in only a few MB of unused free memory. But it also maxed out my CPU and made Application_Start take way too long.

My questions are:

1) What can cause the reported size of the Gen 0 Heap to grow so large?

2) Is this a problem? In particular, could it be causing a large amount of unused space to be allocated to .NET?

3) If so, what should I do to fix it? If I can't prevent the process from using that much memory during Application_Start, I'd like to at least be able to make it give up the memory when app start completes.

like image 647
Tim Goodman Avatar asked Jan 06 '12 20:01

Tim Goodman


1 Answers

Gen 0 contains the "the youngest, most recently allocated objects", and is separate and distinct from the LOH. What it sounds like is that you are allocating tons and tons of small objects (all of the errata associated with those cache entries, by the sound of it) which are unrooted (demonstrated by the frequent GC's keeping the size down) but not cleaned up in a timely manner because the GC hasn't deemed it necessary yet. The GC simply has not yet seen a need to clean up. How much RAM does the machine have? I am guessing that you are not paging.

My understanding is that .NET can return chunks of unused heap to the OS when the GC deems it is no longer needed (because that heap space hasn't been used for a long time, for example). Have you observed the app over a long period of time, to see whether this happens? If you are not paging, I don't think it is a problem.

like image 101
Chris Shain Avatar answered Sep 22 '22 11:09

Chris Shain