Excessive Gen 2 Collections
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:
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.
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.
I tried other tools as well. Red Gate Memory Profiler. That didn't help much either.
So here are my questions:
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.
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.
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.
It turned out that I didn't need to read those performance counter values. I just removed them and things are much better.
精彩评论