Take the 2-minute tour ×

I'm having an issue in my application where I am seeing an excessive amount of Gen 2 Garbage Collections. From what I've been reading it sounds like a good ratio of Gen0 : Gen1 : Gen2 collections should be 100:10:1. I am getting very close to 1:1:1. Every collection seems to be a Gen2 collection. I've been trying to track down the cause of this, but I'm not having much luck. Things I've tried:

  1. Used .NET Memory Profiler to see what objects are being created. I had the Perfmon open showing me the Size of the Gen 2 Heap and I tried to take snapshots when it was low and when it was high and then compare the difference. This was partially successful. Then % Time in GC seems to be lower, but there are still as many Gen2 collections as Gen1.

  2. I disabled a major feature in my application and found that it was what was causing the issue. Not sure how this helps, but I thought I'd mention that I have a general idea where in my code the issue is.

  3. I tried other tools as well. Red Gate Memory Profiler. That didn't help much either.

So here are my questions:

  1. What causes the CLR to perform a Gen2 collection over Gen0 or Gen1? I have been reading that it could be the LOH, but I've confirmed this is not my issue.

  2. What other troubleshooting techniques should I use?

Edit: 6/6/2011

It looks to be related to calling System.Diagnostics.PerformanceCounterCategory.GetInstanceNames(). We have a thread that collects various performance counters. It looks like this eventually calls down to a registry read of HKEY_PERFORMANCE_DATA and a value of "230". This looks to be the "Process" category. The data that gets returned is a byte array that is 65000 bytes. Although this is smaller than 85000, it seems like something here is getting put on the LOH. I put a breakpoint in WinDbg on "mscorwks!svr::gc_heap::allocate_large_object".

Edit: 6/7/2011

It for sure is related to getting performance counter data frequently. It is getting byte arrays that are 130,000 bytes just to read on value from the counter. And since I'm doing this frequently, it creating lots of Gen2 collections since they are all going into the LOH. I was thinking using P/Invoke statements to get the counter values instead.

share|improve this question
Are you trying to fix a problem that isn't really a problem? Is your app running slowly or running out of memory? –  Steve Wellens Jun 4 '11 at 15:38
I should mention that it looks like the Gen2 collections seem to happen at a rate of 1 or 2 per second. –  Bryan Jun 4 '11 at 19:04
Well, the original problem I was trying to solve was a client was reporting that the software was slow. We took a look at the performance counters, and I noticed this issue. The % time in GC was averaging about 20%. We have reason to believe that the client's issue is more likely caused by their environment, but I'd still like to understand what is going on here. –  Bryan Jun 4 '11 at 19:05
add comment

2 Answers

Interesting. The fact that things are surviving to GEN2 could imply you are holding onto things a bit much - perhaps you have temporary objects that remain reachable by a longer-lived object, perhaps due to an event subscription or a captured variable closure.

It also sounds like allocations themselves might be high; watch out for vast numbers of temp objects (that are somehow reachable).

But events are IMO the most likely explanation. See if you are failing to unsubscribe temporary objects from events.

share|improve this answer
I am creating a lot of objects. I can see that from the bytes alloc/sec counter. It is very spiky. –  Bryan Jun 4 '11 at 19:03
@Bryan a lot of objects is pretty fair as long as you don't hang on to them... –  Marc Gravell Jun 4 '11 at 20:05
The objects I'm creating are not supposed to live a long time, but they are because the GC is running so much. I think that is what my main question is. What causes the GC to run so frequently? –  Bryan Jun 6 '11 at 13:06
@Bryan - memory pressure, caused in turn by large allocations ;p which sounds a bit circular I realise, but hey: we have no idea what your code is doing ;p –  Marc Gravell Jun 6 '11 at 13:29
I don't know what it is doing either :) –  Bryan Jun 6 '11 at 13:50
show 1 more comment
up vote 0 down vote accepted

It turned out that I didn't need to read those performance counter values. I just removed them and things are much better.

share|improve this answer
add comment

Your Answer


